Comparison
Base64 vs. base64url: zwei Zeichen, die zählen
Dasselbe Alphabet, andere letzte zwei Zeichen, anderes Padding. Einzeiliger Unterschied, völlig andere Einsatzgebiete.
By Buğra SözeriPublished
Kurzfassung. Base64 und base64url sind dieselbe Kodierung, abgesehen von drei in RFC 4648 definierten Details: + wird zu -, / wird zu _, und das Padding = entfällt. Verwenden Sie base64url überall dort, wo der kodierte Wert in einer URL, einem JWT oder einem signierten Cookie unterwegs ist; verwenden Sie Standard-Base64 für E-Mail-Anhänge, HTTP Basic Auth und Data-URIs.
Beide sind in RFC 4648 definiert. Standard-Base64(§4) und base64url(§5) unterscheiden sich in genau drei Details: zwei Alphabet-Ersetzungen und die Behandlung des Paddings. Das war’s. Aber sie zu verwechseln zerstört JWTs, signierte Cookies und alles andere, was in einer URL unterwegs ist.
Der Unterschied
| Eigenschaft | Standard-Base64 | Base64url |
|---|---|---|
| 62. Zeichen | + | - |
| 63. Zeichen | / | _ |
| Padding | = auf Vielfaches von 4 | Typischerweise weggelassen |
| URL-sicher? | Nein (+, /, = brauchen Prozentkodierung) | Ja |
| Definiert in | RFC 4648 §4 | RFC 4648 §5 |
Dieselbe Eingabe, beide Kodierungen
Kodierung von https://example.com/?q=hello world:
- Standard:
aHR0cHM6Ly9leGFtcGxlLmNvbS8/cT1oZWxsbyB3b3JsZA== - Base64url:
aHR0cHM6Ly9leGFtcGxlLmNvbS8_cT1oZWxsbyB3b3JsZA
Beachten Sie, dass aus dem / in der Standardform ein _ in base64url wird und das nachgestellte == entfällt.
Warum URLs ihre eigene Variante brauchen
Das Standard-Base64-Alphabet enthält + und/. Beide sind in der URL-Syntax reserviert:
/ist der Pfadtrenner.+wird per Konvention in formularkodierten Query-Strings als Leerzeichen interpretiert.=ist der Schlüssel-Wert-Trenner in Query-Strings.
Einen Standard-Base64-String in eine URL einzubetten erfordert die Prozentkodierung aller drei: +wird zu %2B, / wird zu%2F, = wird zu %3D. Der String wird länger und schwerer lesbar. base64url vermeidet die Prozentkodierung, indem es Zeichen wählt, die bereits URL-sicher sind.
Warum Padding in base64url optional ist
Standard-Base64 füllt die Ausgabe stets mit = auf ein Vielfaches von 4 Zeichen auf. Das ist nicht mathematisch notwendig — der Decoder kann die ursprüngliche Länge aus der Ausgabelänge modulo 4 ableiten. Padding existiert für Streaming-Decoder, die die Grenze zwischen aneinandergereihten Chunks kennen müssen.
Base64url überspringt das Padding, weil: (a) es redundant ist, (b) = in URLs prozentkodiert werden muss und (c) nachgestellte Gleichheitszeichen in URLs mitunter Pfadparser, CDNs und Cache-Schlüssel verwirren.
Wo welche verwendet wird
| Einsatzfall | Variante |
|---|---|
| E-Mail-Anhänge (MIME) | Standard-Base64 |
HTTP Basic Auth (Authorization: Basic …) | Standard-Base64 |
Data-URIs (data:image/png;base64,…) | Standard-Base64 |
| JWT (alle drei Segmente) | Base64url, kein Padding |
| OAuth 2.0 PKCE Code-Verifier/-Challenge | Base64url, kein Padding |
| WebPush-Nachrichtenschlüssel, JOSE/JWS/JWE | Base64url, kein Padding |
| Signierte Cookies (Rails, Django usw.) | Base64url, kein Padding |
Die Dekodierungsfalle
Der Standard-Base64-Decoder vieler Bibliotheken scheitert an base64url-Eingaben. Pythons base64.b64decodelehnt - und _ab; Node.js’ Buffer.from(s, "base64")ist nachsichtig, doch die Umkehrung (.toString("base64")) gibt Standard-Base64 aus.
Sprachübergreifende Tricks: vor dem Dekodieren ersetzen.
// base64url → standard Base64
const standard = base64url
.replace(/-/g, "+")
.replace(/_/g, "/")
.padEnd(Math.ceil(base64url.length / 4) * 4, "=");Besser: Verwenden Sie eine Bibliothek, die base64url explizit unterstützt (Node 16+ hat Buffer.from(s, "base64url"); Python hat base64.urlsafe_b64decode).
Die pragmatische Regel
Wenn der kodierte Wert in einer URL, einem JWT, einem signierten Cookie oder als Pfadsegment erscheint — verwenden Sie base64url. Wenn er für einen E-Mail-Anhang, einen HTTP-Header (außer Cookies) oder eine JSON-Data-URI ist — verwenden Sie Standard-Base64.
Unser Base64-Encoderbeherrscht beide Varianten, mit einem Umschalter für das Alphabet. Der JWT-Decoder nimmt base64url an, weil der Standard es verlangt.
Zahlenfakten
- Kodierte Länge: beide Varianten dehnen Binärdaten um genau 4/3 (
ceil(n/3)*4). 100 Eingabebytes → 136 Ausgabezeichen in Standard-Base64 oder 134 Zeichen ohne Padding in base64url. - Padding-Overhead: Standard-Base64 fügt pro kodiertem String 0, 1 oder 2
=-Zeichen hinzu — höchstens 1,5 % Größenaufschlag bei kurzen Nutzdaten, vernachlässigbar bei langen. - Prozentkodierungskosten in URLs: jedes
+ / =in Standard-Base64 dehnt sich beim URL-Kodieren auf 3 Bytes (%2B %2F %3D) aus. Bei einem 512-Zeichen-JWT sind das typischerweise 30–60 verschwendete Bytes — base64url vermeidet es vollständig. - Alphabetgröße: 64 Zeichen in beiden, also trägt jedes Ausgabezeichen genau 6 Bit Eingabe.
- JWT-Segmentgrößen (RFC 7519): typischer Header 40–50 Zeichen, Payload 100–400 Zeichen, HS256-Signatur 43 Zeichen (genau 32 Bytes / 6 = 43 base64url-Zeichen, ohne Padding).
- Durchsatz: Node 20
Buffer.from(s, "base64")dekodiert mit ~2 GB/s; Pythonbase64.b64decodemit ~600 MB/s auf einem Laptop von 2024.
Entscheidungsmatrix
| Wo der Wert lebt | Wahl |
|---|---|
| URL-Pfad oder Query-String | base64url, kein Padding |
| JWT (Header / Payload / Signatur) | base64url, kein Padding (RFC 7519) |
| OAuth 2.0 PKCE Verifier | base64url, kein Padding (RFC 7636 §4.1) |
| Signiertes Cookie (Rails / Django / Express) | base64url, kein Padding |
data:-URI in HTML/CSS | Standard-Base64 mit Padding |
| MIME-E-Mail-Anhang | Standard-Base64 mit Padding, 76-Zeichen-Zeilenumbruch (RFC 2045) |
| HTTP-Basic-Auth-Header | Standard-Base64 (RFC 7617) |
| WebPush-Abonnementschlüssel | base64url, kein Padding (RFC 8291) |
Quellen
- RFC 4648 — The Base16, Base32, and Base64 Data Encodings — rfc-editor.org/rfc/rfc4648 (§4 Standard, §5 URL-sicher).
- RFC 7519 — JSON Web Token (JWT), schreibt base64url ohne Padding vor — rfc-editor.org/rfc/rfc7519.
- RFC 7636 — OAuth 2.0 PKCE, §4.1 spezifiziert die base64url-kodierte SHA-256-Challenge — rfc-editor.org/rfc/rfc7636.
Frequently asked questions
- Kann ich base64url mit einem Standard-Base64-Decoder dekodieren?
- Manchmal — Nodes Buffer.from ist nachsichtig, Pythons b64decode nicht. Der sprachübergreifend sichere Ansatz: ersetzen Sie '-' durch '+', '_' durch '/' und füllen Sie vor dem Dekodieren mit '=' auf ein Vielfaches von 4 auf. Moderne Laufzeiten bieten explizite base64url-Decoder (Node 16+, Pythons urlsafe_b64decode), die das direkt erledigen.
- Warum lässt base64url das Padding weg?
- Drei Gründe: Es ist mathematisch redundant (Decoder können die ursprüngliche Länge aus der Ausgabelänge modulo 4 ableiten), das '='-Zeichen muss in URLs prozentkodiert werden, und nachgestellte '=' verwirren manche Pfadparser, CDNs und Cache-Schlüssel.
- Sind JWT-Segmente immer base64url?
- Ja. RFC 7519 schreibt base64url ohne Padding für alle drei JWT-Segmente (Header, Payload, Signatur) vor. Ein JWT mit Standard-Base64 zu kodieren erzeugt ein Token, das in keiner konformen Bibliothek verifiziert wird.
- Spart base64url Bytes gegenüber Standard-Base64?
- Geringfügig — dieselbe Alphabetgröße bedeutet vor dem Padding dieselbe kodierte Länge. Das Weglassen des Paddings spart 0–2 Bytes pro Kodierung. Die eigentliche Ersparnis ist das Vermeiden der Prozentkodierung (jedes %XX sind 3 Bytes statt 1), was pro Base64-String in einer URL 6–9 Bytes sparen kann.
Related
Published May 16, 2026