134 Stimmen

RegEx zum Parsen oder Validieren von Base64-Daten

Ist es möglich, ein RegEx zu verwenden, um Base64-Daten zu validieren oder zu bereinigen? Das ist die einfache Frage, aber die Faktoren, die diese Frage antreiben, machen sie schwierig.

Ich habe einen Base64-Decoder, der sich nicht vollständig darauf verlassen kann, dass die Eingabedaten den RFC-Spezifikationen entsprechen. Die Probleme, mit denen ich konfrontiert bin, sind also Probleme wie z. B. Base64-Daten, die möglicherweise nicht in 78 (ich glaube, es sind 78, ich müsste den RFC noch einmal überprüfen, also bitte nicht meckern, wenn die genaue Zahl falsch ist) Zeichenzeilen aufgeteilt sind, oder dass die Zeilen möglicherweise nicht mit CRLF enden, sondern nur ein CR oder LF oder vielleicht keines von beiden enthalten.

Ich hatte also verdammt viel Mühe mit dem Parsen von Base64-Daten, die als solche formatiert sind. Aus diesem Grund sind Beispiele wie die folgenden nicht mehr zuverlässig zu entschlüsseln. Der Kürze halber werde ich nur einen Teil der MIME-Header anzeigen.

Content-Transfer-Encoding: base64

VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Das zu analysieren ist also kein Problem und entspricht genau dem Ergebnis, das wir erwarten würden. Und in 99 % der Fälle funktioniert die Verwendung eines Codes, der zumindest überprüft, ob jedes Zeichen im Puffer ein gültiges base64-Zeichen ist, perfekt. Aber das nächste Beispiel wirft einen Schraubenschlüssel in den Mix.

Content-Transfer-Encoding: base64

http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Dies ist eine Version der Base64-Kodierung, die ich in einigen Viren und anderen Dingen gesehen habe, die versuchen, den Wunsch einiger E-Mail-Leser auszunutzen, Mime um jeden Preis zu parsen, im Gegensatz zu denen, die sich strikt an das Buch oder besser gesagt RFC halten.

Mein Base64-Decoder dekodiert das zweite Beispiel in den folgenden Datenstrom. Und denken Sie daran, dass der ursprüngliche Datenstrom ausschließlich aus ASCII-Daten besteht!

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

Hat jemand eine gute Idee, wie man beide Probleme auf einmal lösen kann? Ich bin mir nicht sicher, ob es überhaupt möglich ist, abgesehen davon, dass man zwei Transformationen mit unterschiedlichen Regeln auf die Daten anwenden und die Ergebnisse vergleichen kann. Aber wenn Sie diesen Ansatz wählen, welchem Ergebnis vertrauen Sie dann? Es scheint, dass die ASCII-Heuristik etwa die am besten Lösung, aber wie viel mehr Code, Ausführungszeit und Komplexität würde das zu etwas so Kompliziertem wie einem Virenscanner hinzufügen, an dem dieser Code tatsächlich beteiligt ist? Wie würden Sie die Heuristik trainieren, damit sie lernt, was für Base64 akzeptabel ist und was nicht?


UPDATE:

Da diese Frage immer wieder gestellt wird, habe ich beschlossen, das einfache RegEx zu veröffentlichen, das ich seit 3 Jahren in einer C#-Anwendung mit Hunderttausenden von Transaktionen verwende. Ehrlich gesagt, gefällt mir die Antwort von Gumbo die beste, weshalb ich sie auch als Antwort ausgewählt habe. Aber jeder mit C#, und auf der Suche nach einer sehr schnellen Weg, um zumindest zu erkennen, ob eine Zeichenfolge oder byte[] enthält gültige Base64-Daten oder nicht, ich habe die folgenden sehr gut für mich arbeiten gefunden.

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

Und ja, das ist nur für eine STRING von Base64-Daten, NICHT eine richtig formatierte RFC1341 Nachricht. Wenn Sie also mit Daten dieses Typs zu tun haben, sollten Sie dies berücksichtigen, bevor Sie versuchen, das obige RegEx zu verwenden. Wenn Sie mit Base16, Base32, Radix oder sogar Base64 für andere Zwecke arbeiten (URLs, Dateinamen, XML-Kodierung usw.), dann ist es sehr empfehlen, dass Sie lesen RFC4648 dass Gumbo in seiner Antwort erwähnt, da Sie sich über den Zeichensatz und die Terminatoren, die von der Implementierung verwendet werden, im Klaren sein müssen, bevor Sie versuchen, die Vorschläge in diesem Frage/Antwort-Set zu verwenden.

0 Stimmen

Ich denke, dass man die Aufgabe besser definieren muss. Es ist völlig unklar, was Ihr Ziel ist: streng sein? 100% der Proben analysieren? ...

0 Stimmen

Ihr erstes Beispiel sollte 'VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4=' lauten.

1 Stimmen

Warum verwenden Sie nicht eine Standardlösung in Ihrer Sprache? Warum brauchen Sie einen handgeschriebenen Parser auf der Grundlage von Regexen?

185voto

Gumbo Punkte 617646

Von der RFC 4648 :

Die Basiskodierung von Daten wird in vielen Situationen verwendet, um Daten in Umgebungen zu speichern oder zu übertragen, die, vielleicht aus alten Gründen, auf US-ASCII-Daten beschränkt sind.

Es hängt also vom Verwendungszweck der verschlüsselten Daten ab, ob die Daten als gefährlich eingestuft werden sollten.

Wenn Sie jedoch nur nach einem regulären Ausdruck suchen, der mit Base64-kodierten Wörtern übereinstimmt, können Sie Folgendes verwenden:

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

48voto

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

Dieser ist gut, passt aber zu einem leeren String

Dieser stimmt nicht mit der leeren Zeichenkette überein:

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

10voto

Pedro Gimeno Punkte 2305

Die bisher vorgestellten Antworten prüfen nicht, ob die Base64-Zeichenkette alle Pad-Bits auf 0 gesetzt hat, was erforderlich ist, um die kanonische Darstellung von Base64 zu sein (was in einigen Umgebungen wichtig ist, siehe https://www.rfc-editor.org/rfc/rfc4648#section-3.5 ) und daher erlauben sie Aliasnamen die unterschiedliche Kodierungen für dieselbe binäre Zeichenfolge sind. Dies könnte in einigen Anwendungen ein Sicherheitsproblem darstellen.

Hier ist der Regexp, der überprüft, ob die angegebene Zeichenkette nicht nur eine gültige base64-Zeichenkette ist, sondern auch die kanonische base64-Zeichenkette für die Binärdaten:

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

Der zitierte RFC betrachtet die leere Zeichenkette als gültig (siehe https://www.rfc-editor.org/rfc/rfc4648#section-10 ), also tut es die obige Regex auch.

Der äquivalente reguläre Ausdruck für base64url (siehe wiederum den oben genannten RFC) lautet:

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

6voto

Paul Punkte 61

Hier ist ein alternativer regulärer Ausdruck:

^(?=(.{4})*$)[A-Za-z0-9+/]*={0,2}$

Sie erfüllt die folgenden Bedingungen:

  • Die Länge der Zeichenkette muss ein Vielfaches von vier sein - (?=^(.{4})*$)
  • Der Inhalt muss aus alphanumerischen Zeichen oder + oder / - bestehen. [A-Za-z0-9+/]*
  • Er kann bis zu zwei Auffüllungszeichen (=) am Ende haben - ={0,2}
  • Sie akzeptiert leere Zeichenketten

5voto

oylenshpeegul Punkte 3374

Weder ein " : " noch ein " . " wird in gültigem Base64 auftauchen, also denke ich, dass man die http://www.stackoverflow.com Zeile. In Perl, zum Beispiel, etwas wie

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

say decode_base64($sanitized_str);

könnte das sein, was Sie wollen. Es produziert

Dies ist ein einfaches ASCII Base64 Beispiel für StackOverflow.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X