129 votes

RegEx pour analyser ou valider les données Base64

Est-il possible d'utiliser un RegEx pour valider ou assainir des données Base64 ? C'est une question simple, mais les facteurs qui la motivent la rendent difficile.

J'ai un décodeur Base64 qui ne peut pas se fier entièrement aux données d'entrée pour suivre les spécifications RFC. Ainsi, les problèmes auxquels je suis confronté sont des problèmes tels que des données Base64 qui peuvent ne pas être divisées en 78 (je pense que c'est 78, il faudrait que je vérifie le RFC, alors ne me faites pas de reproches si le nombre exact est erroné) lignes de caractères, ou que les lignes peuvent ne pas se terminer par CRLF ; en ce sens qu'elles peuvent n'avoir qu'un CR, ou LF, ou peut-être ni l'un, ni l'autre.

J'ai donc eu beaucoup de mal à analyser les données Base64 formatées comme telles. De ce fait, des exemples comme celui-ci deviennent impossibles à décoder de manière fiable. Par souci de concision, je n'afficherai que des en-têtes MIME partiels.

Content-Transfer-Encoding: base64

VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Ok, l'analyse n'est pas un problème, et c'est exactement le résultat que nous attendions. Et dans 99% des cas, l'utilisation d'un code pour au moins vérifier que chaque caractère dans le tampon est un caractère base64 valide, fonctionne parfaitement. Mais l'exemple suivant jette un pavé dans la mare.

Content-Transfer-Encoding: base64

http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Il s'agit d'une version de l'encodage Base64 que j'ai vue dans certains virus et autres choses qui tentent de profiter du désir de certains lecteurs de courrier d'analyser le mime à tout prix, par opposition à ceux qui suivent strictement les règles, ou plutôt les RFC, si vous voulez.

Mon décodeur Base64 décode le deuxième exemple en un flux de données. N'oubliez pas que le flux d'origine est constitué de données ASCII !

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

Quelqu'un a-t-il un bon moyen de résoudre les deux problèmes à la fois ? Je ne suis pas sûr que ce soit possible, si ce n'est en effectuant deux transformations sur les données avec des règles différentes, et en comparant les résultats. Cependant, si vous adoptez cette approche, à quel résultat faites-vous confiance ? Il semble que l'heuristique ASCII soit à peu près la plus fiable. meilleur mais combien de code, de temps d'exécution et de complexité supplémentaires cela ajouterait-il à quelque chose d'aussi compliqué qu'un scanner de virus, dans lequel ce code est en fait impliqué ? Comment entraîner le moteur heuristique à apprendre ce qui est acceptable en Base64 et ce qui ne l'est pas ?


UPDATE :

Vu le nombre de vues que cette question continue de recevoir, j'ai décidé de publier le simple RegEx que j'utilise dans une application C# depuis 3 ans maintenant, avec des centaines de milliers de transactions. Honnêtement, j'aime la réponse donnée par Gumbo le meilleur, c'est pourquoi je l'ai choisi comme réponse sélectionnée. Mais pour tous ceux qui utilisent C# et qui cherchent un moyen très rapide de détecter au moins si une chaîne de caractères ou un octet[] contient des données Base64 valides ou non, j'ai trouvé ce qui suit qui fonctionne très bien pour moi.

[^-A-Za-z0-9+/=]|=[^=]|={3,}$

Et oui, c'est juste pour une CHAÎNE de données Base64, PAS d'un fichier correctement formaté. RFC1341 message. Par conséquent, si vous traitez des données de ce type, tenez-en compte avant d'essayer d'utiliser le RegEx ci-dessus. Si vous avez affaire à des données en Base16, Base32, Radix ou même Base64 à d'autres fins (URL, noms de fichiers, encodage XML, etc.), il est possible d'utiliser le RegEx suivant très vous recommande de lire RFC4648 que Gumbo mentionné dans sa réponse, car vous devez bien connaître le jeu de caractères et les terminateurs utilisés par l'implémentation avant d'essayer d'utiliser les suggestions de cette série de questions/réponses.

181voto

Gumbo Points 279147

A partir de la RFC 4648 :

Le codage de base des données est utilisé dans de nombreuses situations pour stocker ou transférer des données dans des environnements qui, peut-être pour des raisons historiques, sont limités aux données US-ASCII.

La question de savoir si les données codées doivent être considérées comme dangereuses dépend donc de l'usage qui en est fait.

Mais si vous cherchez simplement une expression régulière pour faire correspondre des mots encodés en Base64, vous pouvez utiliser ce qui suit :

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$

48voto

njzk2 Points 17085
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$

Celui-ci est bon, mais il correspondra à une chaîne vide.

Celui-ci ne correspond pas à la chaîne vide :

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$

10voto

Pedro Gimeno Points 109

Les réponses présentées jusqu'à présent ne vérifient pas que tous les bits de la chaîne Base64 sont à 0, ce qui est nécessaire pour qu'il s'agisse de la représentation canonique de Base64 (ce qui est important dans certains environnements, voir https://www.rfc-editor.org/rfc/rfc4648#section-3.5 ) et, par conséquent, ils autorisent les alias qui sont des encodages différents pour la même chaîne binaire. Cela peut poser un problème de sécurité dans certaines applications.

Voici la regexp qui vérifie que la chaîne donnée n'est pas seulement valide en base64, mais aussi la chaîne canonique en base64 pour les données binaires :

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/][AQgw]==|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=)?$

Le RFC cité considère la chaîne vide comme valide (voir https://www.rfc-editor.org/rfc/rfc4648#section-10 ), l'expression rationnelle ci-dessus le fait donc aussi.

L'expression régulière équivalente pour base64url (encore une fois, se référer au RFC ci-dessus) est :

^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-][AQgw]==|[A-Za-z0-9_-]{2}[AEIMQUYcgkosw048]=)?$

5voto

oylenshpeegul Points 3101

Ni un " : "ni un " . "apparaîtra en Base64 valide, donc je pense que vous pouvez sans ambiguïté rejeter l'élément http://www.stackoverflow.com ligne. En Perl, par exemple, quelque chose comme

my $sanitized_str = join q{}, grep {!/[^A-Za-z0-9+\/=]/} split /\n/, $str;

say decode_base64($sanitized_str);

pourrait être ce que vous voulez. Il produit

Il s'agit d'un simple ASCII Base64 pour l'exemple de StackOverflow.

5voto

La meilleure regexp que j'ai pu trouver jusqu'à présent se trouve ici https://www.npmjs.com/package/base64-regex

qui, dans la version actuelle, ressemble à ce qui suit :

module.exports = function (opts) {
  opts = opts || {};
  var regex = '(?:[A-Za-z0-9+\/]{4}\\n?)*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)';

  return opts.exact ? new RegExp('(?:^' + regex + '$)') :
                    new RegExp('(?:^|\\s)' + regex, 'g');
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X