Deutsch

Entwicklertools · Base64-Encoder und -Decoder

RFC 4648 erklärt: der Standard, der Base64, base32 und base16 definiert

· Hintergrund

base64 Kodierung

RFC 4648 Alphabetfamilien: base64, base64url, base32, base32hex, base16
Original-ToolAcre-Vektorillustration

RFC 4648 ist das kurze, lesbare Dokument hinter jeder Base64-Implementierung. In diesem Beitrag geht es darum, was er spezifiziert, was er bewusst offen lässt und warum sich die Implementierungen immer noch unterscheiden.

Zwei Bibliotheken, zwei Antworten für dieselbe Zeichenfolge – ein echtes Interoperabilitätsrätsel, das nur der Standard löst

Zwei JavaScript-Bibliotheken können unterschiedliche Base64-Werte für denselben String zurückgeben, wobei jede den Anspruch auf Korrektheit erhebt. RFC 4648 ist das lesbare zwölfseitige Dokument, das solche Meinungsverschiedenheiten beilegen soll. Die Implementierungen unterscheiden sich jedoch immer noch, da der RFC bestimmte Entscheidungen bewusst den Anwendungen überlässt. In diesem Artikel wird erläutert, was RFC 4648 spezifiziert, was es absichtlich an Aufrufer delegiert und warum das einmalige Lesen des Standards die meisten echten Interoperabilitätsprobleme löst. Das Base64-Encoder- und Decoder-Tool enthält RFC-Testvektoren 4648, sodass Sie eine Implementierung anhand der maßgeblichen Beispiele überprüfen können.

RFC 4648 ersetzte und konsolidierte mehrere frühere Dokumente: Base64 von MIME (RFC 2045), Base64 von Privacy-Enhanced Mail (RFC 1421), base32 von S/MIME (RFC 2630) und base16 aus verschiedenen Quellen. Die Konsolidierung war notwendig, da MIME und PEM jeweils über ein eigenes Alphabet und eigene Regeln verfügten und der MIME-Zeilenumbruch mit den 64-Spaltenblöcken von PEM in Konflikt stand. RFC 4648 definiert fünf Codierungsfamilien an einem Ort: base64, base64url, base32, base32hex und base16, jede mit ihrem eigenen Alphabet, Füllregeln und Beispieltestvektoren. Das Base64-Alphabet ist A-Z, a-z, 0-9, plus und Schrägstrich, in dieser Reihenfolge.

Was die Implementierungs- und Testvektoren festlegen – Standard- und URL-sichere Alphabete, Auffüllung und Umgang mit Leerzeichen

Jedes Zeichen repräsentiert 6 Bits; Drei Eingabebytes (24 Bits) werden vier Ausgabezeichen zugeordnet. Das Alphabet ist nicht willkürlich: Es vermeidet Zeichen, die sich zwischen EBCDIC und ASCII unterscheiden, und vermeidet Steuerzeichen, Anführungszeichen und den Backslash, der in C-String-Literalen maskiert werden müsste. Die base64url-Variante ersetzt Plus durch Bindestrich und Schrägstrich durch Unterstrich, um reservierte Zeichen in URLs und Dateinamen zu vermeiden. Beide Varianten sind gleichermaßen gültig; RFC 4648 Abschnitt 2 gibt Base64 an, Abschnitt 5 gibt Base64-URL an und eine Anwendung muss angeben, welche sie verwendet.

Durch Auffüllen mit Gleichheitszeichen wird die Ausgabe auf ein Vielfaches von vier Zeichen gebracht. Wenn die Eingabe 1 Byte (8 Bits) ist, besteht die Ausgabe aus zwei Zeichen plus zwei Gleichheitszeichen. Wenn die Eingabe 2 Bytes (16 Bits) umfasst, besteht die Ausgabe aus drei Zeichen plus einem Gleichheitszeichen. Wenn die Eingabe ein Vielfaches von 3 Bytes ist, ist kein Auffüllen erforderlich. Einige Anwendungen lassen Auffüllungen weg oder erlauben fehlende Auffüllungen bei der Dekodierung. RFC 4648 Abschnitt 3.2 definiert die kanonische Codierung als immer aufgefüllt, aber Abschnitt 3.3 weist darauf hin, dass Decoder aus Kompatibilitätsgründen möglicherweise fehlende Auffüllungen akzeptieren.

Die von diesem Tool implementierten Alphabete – Standard Base64 und Base64url; andere Stützpunkte bleiben außerhalb ihres Geltungsbereichs

Der Auffüllunterschied ist der Grund, warum Implementierungen unterschiedlicher Meinung sind: Ein strikter Decoder lehnt fehlende Gleichheitswerte ab, während ein milderer Decoder dies akzeptiert. In RFC 4648 heißt es ausdrücklich: Das Füllzeichen „equals“ ist in der Regel prozentcodiert, wenn es in URLs verwendet wird. Wenn also die base64url-Ausgabe direkt in einem URL-Parameter verwendet wird, ist das Füllzeichen nicht erforderlich und sollte weggelassen werden. Dieser Satz ist einer der Gründe dafür, dass der URL-sichere Modus und das Auslassen von Auffüllungen oft gepaart werden, obwohl es sich dabei um unabhängige Optionen handelt. Abschnitt 5 (base64url) verbietet das Auffüllen nicht; es wird lediglich auf die gängige Praxis hingewiesen.

Ein Anrufer, der base64url wählt, muss entscheiden, ob Auffüllen für das empfangende System erforderlich ist. Nicht-alphabetische Zeichen in der Eingabe werden von verschiedenen Decodern unterschiedlich behandelt. RFC 4648 Abschnitt 3.1 besagt: Implementierungen MÜSSEN die Codierung ablehnen, wenn sie Zeichen außerhalb des Basisalphabets enthält. Abschnitt 3.3 weist jedoch darauf hin, dass MIME Base64 (RFC 2045) Zeilenumbrüche für 76-Zeichenumbrüche zulässt und Decoder für MIME Leerzeichen überspringen müssen. Der RFC unterscheidet zwischen strikter Dekodierung (alle Nicht-Alphabet-Zeichen ablehnen) und MIME-kompatibler Dekodierung (Leerzeichen überspringen, andere Zeichen ablehnen).

Auffüllung, Nicht-Alphabet-Zeichen und kanonische Kodierung – die Abschnitte, die die meisten Meinungsverschiedenheiten bei Decodern erklären

Eine Anwendung muss auswählen, welche Regel befolgt werden soll. Der Standard definiert beides. Base32 verwendet A-Z und 2-7 (insgesamt 32 Zeichen) und kodiert fünf Eingabebytes (40 Bits) in acht Ausgabezeichen. Base32hex ersetzt 0-9 und a-v für die alphabetischen Zeichen, was in Kontexten nützlich ist, in denen Kleinbuchstaben bevorzugt werden.

Base16 ist hexadezimal: 0-9 und a-f. Base32 und base32hex haben ihre eigenen Auffüllregeln in den Abschnitten 6 und 7, und der RFC stellt für jedes Alphabet separate Testvektoren bereit. Die meisten Entwickler benötigen nur base64 und base64url; Der Vollständigkeit halber und für Anwendungen wie TOTP-Geheimnisse (RFC 4226) und DNS-Kodierung sind base32, base32hex und base16 im RFC enthalten.

In dieser Implementierung sichtbare Anwendungsoptionen – Zeilenumbruch, strikte Textdekodierung und Fehlerbehandlung

Die Testvektoren in RFC 4648 sind die Grundwahrheit für die Überprüfung einer Implementierung. Die Codierung der Zeichenfolgen f, fo, foo, foob, fooba und foobar erzeugt eine spezifische Base64-Ausgabe: Zg==, Zm8=, Zm9v, Zm9vYg==, Zm9vYmE= und Zm9vYmFy. Eine Implementierung, die für diese Zeichenfolgen eine andere Ausgabe erzeugt, ist falsch. Der RFC stellt äquivalente Testvektoren für Base32, Base32hex und Base16 bereit. Das Base64-Encoder- und Decoder-Tool enthält diese Vektoren, sodass Sie die Ausgabe anhand des Standards überprüfen können. Der Zeilenumbruch ist ein MIME-Problem, kein Base64-Problem.

RFC 2045 gibt 76-Zeichenzeilen an; RFC 4648 Abschnitt 3.1 vermerkt dies im Kontext von MIME, macht es jedoch nicht zu einer Anforderung von Base64 selbst. Einige Anwendungen werden mit 64 Zeichen umgebrochen (der ursprüngliche PEM-Standard); andere wickeln überhaupt nicht ein. Ein strikter RFC 4648 Base64-Decoder arbeitet nur mit dem Alphabet und der Auffüllung. Ein MIME-kompatibler Decoder muss Zeilenumbrüche (CR, LF, CRLF) überspringen. Eine Anwendung, die Base64 außerhalb von MIME verwendet, sollte keine Zeilenumbrüche hinzufügen, es sei denn, das empfangende System erfordert sie; Der RFC definiert keinen Zeilenumbruch als Teil von Base64.

Arbeitsbeispiel: die RFC-eigenen Testvektoren – Kodierung der „foobar“-Präfixe und Überprüfung dieser im Browser

Die Handhabung von Leerzeichen ist ein weiterer Punkt der Implementierungsabweichung. RFC 4648 besagt, dass strikte Decoder Nicht-Alphabet-Zeichen ablehnen müssen. Mit MIME umschlossenes Base64 (RFC 2045 base64) ermöglicht Leerzeichen für die Formatierung. Die beiden Standards stimmen darin überein, was die Ausgabebytes sein sollten, unterscheiden sich jedoch darin, welche Eingabe gültig ist. Die meisten JavaScript-Implementierungen wählen MIME-Kompatibilität und überspringen Leerzeichen. Die strenge Regel wird in Browsern selten verwendet. Der Base64-Encoder und -Decoder akzeptiert sowohl Leerzeichen enthaltende (MIME) als auch strikte Eingaben, wodurch die Unterscheidung explizit gemacht wird. Kanonische vs. nachsichtige Dekodierung ist der letzte große Unterschied.

Die kanonische Dekodierung folgt RFC 4648 Abschnitt 3.2: fehlerhafte Auffüllungen ablehnen, fehlende Auffüllungen ablehnen, nicht alphabetische Zeichen ablehnen. Die in Webstandards verwendete fehlerverzeihende Dekodierung (die HTML-Spezifikation nennt sie „forgiving-base64“) fügt Regeln hinzu: Ignorieren Sie Leerzeichen, akzeptieren Sie fehlende Auffüllungen, erlauben Sie Bindestriche und Unterstriche als Plus-Schrägstrich-Äquivalente, selbst im Standard-Base64-Modus. atob() von JavaScript verzeiht; Ein strenger RFC-Decoder 4648 ist strenger. Beides ist nicht falsch; Sie dienen unterschiedlichen Kontexten. Eine Anwendung, die Daten von einem Benutzer oder aus dem Netzwerk liest, sollte wissen, welche Regel die andere Seite erwartet.

Was hiervon nicht abgedeckt wird: die MIME- und PEM-Dokumente selbst sowie sprachspezifische APIs

Der RFC lässt der Anwendung neun Wahlmöglichkeiten: Welches der fünf Alphabete, ob Auffüllen erforderlich oder zulässig ist, ob Leerzeichen erforderlich oder zulässig sind, ob Bindestrich-Unterstriche als Plus-Schrägstrich-Äquivalente behandelt werden sollen, wie Fehler gemeldet werden, wie mit dem Ende der Eingabe umgegangen wird, ob fehlende Auffüllungen akzeptiert werden sollen, wie viele Ausgabebytes zugewiesen werden sollen und wie eine Größenbeschränkung signalisiert werden soll. Diese Auswahl erklärt, warum zwei RFC-4648-Implementierungen bei derselben Eingabe unterschiedlich sein können. Lesen Sie den RFC einmal; Überprüfen Sie Ihre Implementierung anhand ihrer Testvektoren. Geben Sie an, welche Optionen Ihre Anwendung verwendet. Testen Sie die Interoperabilität mit dem tatsächlichen Peer, nicht Annahmen.

RFC verstehen 4648 löst die meisten Base64-Streitigkeiten, da es bei Meinungsverschiedenheiten normalerweise nicht um den RFC selbst geht, sondern darum, welche Optionen jede Seite gewählt hat. Der RFC ist kurz genug, um ihn in einer Stunde vollständig zu lesen. Der Standard definiert die Alphabete, stellt Testvektoren bereit und warnt, wo Implementierungen entscheiden müssen. Mit dem Base64-Encoder- und Decoder-Tool können Sie mit den Testvektoren experimentieren und das Standardalphabet in Aktion sehen. Für die meisten alltäglichen Base64-Anwendungen sind keine tiefgreifenden RFC-Kenntnisse erforderlich. Wenn Sie jedoch Codierungskonflikte beheben oder eine Integration mit einer unbekannten API durchführen, müssen Sie den Standard einmal lesen, um Rätselraten zu vermeiden.

Takeaway: Lesen Sie den Standard einmal – wie Sie mit dem Base64-Encoder und -Decoder schnell die Testvektoren des Standardalphabets überprüfen können

RFC 4648 ist die Konsolidierung jahrzehntelanger Ad-hoc-Basiskodierungspraxis in einer lesbaren Spezifikation. Es definiert nicht, wann Base64 verwendet werden soll (MIME, PEM, JWT, Daten-URIs usw. haben jeweils ihre eigenen Spezifikationen); Es definiert, was base64 ist. Durch die Definition von fünf Codierungsfamilien und die Angabe, welche Optionen kanonisch sind, ermöglicht der RFC die Überprüfung, ob eine Implementierung korrekt ist. Die maßgeblichen Testvektoren sind der Ausgangspunkt: Wenn Ihre Implementierung foobar codiert und etwas anderes als Zm9vYmFy produziert, sagt der RFC, dass die Implementierung falsch ist.

Verwenden Sie diese Autorität als Prüfpunkt für die Überprüfung: Codieren Sie jeden RFC-Testvektor, vergleichen Sie die genauen Zeichen und decodieren Sie dann das Ergebnis, um zu bestätigen, dass die ursprünglichen Bytes unverändert zurückgegeben werden. Diese browserbasierte Prüfung trennt einen Alphabet- oder Auffüllfehler von einem Problem an anderer Stelle in einer Integration, wobei der Standard selbst als Referenz beibehalten wird und nicht auf eine Bibliotheksbezeichnung zurückgegriffen werden muss.