Est-il possible d'utiliser un RegEx pour valider ou assainir les données Base64? C'est la question simple, mais les facteurs qui motivent cette question sont ce qui la rend difficile.
J'ai un décodeur Base64 qui ne peut pas entièrement compter sur les données d'entrée pour suivre les spécifications RFC. Donc, les problèmes auxquels je suis confronté sont des problèmes tels que peut-être les données Base64 qui pourraient ne pas être divisées en 78 (je pense que c'est 78, il faudrait que je vérifie la RFC, alors ne me touchez pas si le nombre exact est faux) lignes, ou que les lignes ne peuvent pas se terminer par CRLF; en ce sens qu'il ne peut avoir qu'un CR, ou un FL, ou peut-être ni l'un ni l'autre.
J'ai donc passé beaucoup de temps à analyser des données Base64 formatées comme telles. Pour cette raison, des exemples comme ceux-ci deviennent impossibles à décoder de manière fiable. J'afficherai seulement les en-têtes MIME partiels par souci de concision.
Content-Transfer-Encoding: base64
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
Ok, donc l'analyse n'est pas un problème, et c'est exactement le résultat auquel nous nous attendions. Et dans 99% des cas, utiliser n'importe quel code pour vérifier au moins que chaque caractère du tampon est un caractère base64 valide fonctionne parfaitement. Mais l'exemple suivant introduit une clé dans le mélange.
Content-Transfer-Encoding: base64
http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
C’est une version de l’encodage Base64 que j’ai vue dans certains virus et autres éléments qui tente de tirer parti de la volonté de certains lecteurs de courrier d’analyser le mime à tout prix, par opposition à ceux strictement conformes au livre, ou plutôt à la RFC; si vous voulez.
Mon décodeur Base64 décode le deuxième exemple du flux de données suivant. Et gardez à l’esprit ici, le flux original contient toutes les données ASCII!
[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8
Quelqu'un at-il un bon moyen de résoudre les deux problèmes à la fois? Je ne suis pas sûr que ce soit même possible, à part d'effectuer deux transformations sur les données avec des règles différentes appliquées et de comparer les résultats. Cependant, si vous avez choisi cette approche, en quelle production faites-vous confiance? Il semble que l'heuristique ASCII concerne la solution meilleure, mais combien de code, de temps d'exécution et de complexité cela ajouterait-il à quelque chose d'aussi compliqué qu'un logiciel de détection de virus, à quoi ce code est réellement impliqué dans? Comment formeriez-vous le moteur heuristique pour savoir ce qui est acceptable en Base64 et ce qui ne l'est pas?
En ce qui concerne le nombre de points de vue que cette question continue d’obtenir, j’ai décidé d’afficher le simple RegEx que j’utilise depuis 3 ans dans une application C #, avec des centaines de milliers de transactions. Honnêtement, j'aime bien la réponse donnée par Gumbo le meilleur, c'est pourquoi je l'ai choisie comme réponse choisie. Mais pour tous ceux qui utilisent C # et qui cherchent un moyen très rapide de détecter au moins si une chaîne ou un octet [] contient des données valides en Base64 ou non, j'ai trouvé que ce qui suit fonctionnait très bien pour moi.
[^-A-Za-z0-9+/=]|=[^=]|={3,}$
Et oui, ceci est juste pour un [~ # ~] chaîne [~ # ~] de données Base64, PAS un message correctement formaté RFC1341 . Donc, si vous traitez avec des données de ce type, veuillez en tenir compte avant d'essayer d'utiliser le RegEx ci-dessus. Si vous utilisez Base16, Base32, Radix ou même Base64 à d’autres fins (URL, noms de fichier, encodage XML, etc.), c’est alors fortement vous recommandons de lire RFC4648 que Gumbo a 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 de tenter d’utiliser les suggestions de cet ensemble de questions/réponses.
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 héritées du passé, sont limités aux données US-ASCII.
Cela dépend donc de la finalité de l'utilisation des données codées si celles-ci doivent être considérées comme dangereuses.
Toutefois, si vous recherchez simplement une expression régulière correspondant aux mots codés en Base64, vous pouvez utiliser les éléments suivants:
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
Celui-ci est bon, mais correspondra à une chaîne vide
Celui-ci ne correspond pas à une chaîne vide:
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$
Ni un ":)" ni un "." n'apparaîtra dans Base64 valide. Je pense donc que vous pouvez jeter sans ambiguïté le http://www.stackoverflow.com
ligne. En Perl, disons 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. Cela produit
C’est simple ASCII Base64 pour un exemple de carte StackOverflow.
La meilleure expression rationnelle que j'ai pu trouver jusqu'à présent se trouve ici https://www.npmjs.com/package/base64-regex
qui est dans la version actuelle ressemble à:
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');
};