Strumenti per sviluppatori · Codificatore e decodificatore Base64
RFC 4648 spiegato: lo standard che definisce Base64, base32 e base16
· Sfondo
base64 codifica
RFC 4648 è il documento breve e leggibile dietro ogni implementazione Base64. Questo post illustra ciò che specifica, ciò che lascia deliberatamente in sospeso e il motivo per cui le implementazioni differiscono ancora.
Due librerie, due risposte per la stessa stringa: un vero e proprio puzzle di interoperabilità che solo lo standard risolve
Due librerie JavaScript possono restituire Base64 diversi per la stessa stringa, ciascuna dichiarando la correttezza. RFC 4648 è il documento leggibile di dodici pagine che dovrebbe risolvere tali disaccordi, tuttavia le implementazioni differiscono ancora perché RFC lascia deliberatamente determinate decisioni alle applicazioni. Questo articolo illustra cosa specifica RFC 4648, cosa delega intenzionalmente ai chiamanti e perché leggere lo standard una volta risolve la maggior parte dei reali enigmi di interoperabilità. Lo strumento di codifica e decodifica Base64 include vettori di test RFC 4648 in modo da poter verificare un'implementazione rispetto agli esempi autorevoli.
RFC 4648 ha sostituito e consolidato diversi documenti precedenti: Base64 da MIME (RFC 2045), Base64 da Privacy-Enhanced Mail (RFC 1421), base32 da S/MIME (RFC 2630) e base16 da varie fonti. Il consolidamento era necessario perché MIME e PEM avevano ciascuno il proprio alfabeto e le proprie regole e il ritorno a capo della riga di MIME era in conflitto con i blocchi di colonne 64 di PEM. RFC 4648 definisce cinque famiglie di codifica in un unico posto: base64, base64url, base32, base32hex e base16, ciascuna con il proprio alfabeto, regole di riempimento e vettori di test di esempio. L'alfabeto base64 è A-Z, a-z, 0-9, più e barra, in quest'ordine.
Cosa stabiliscono i vettori di implementazione e test: alfabeti standard e URL-safe, riempimento e gestione degli spazi bianchi
Ogni carattere rappresenta 6 bits; tre byte di input (24 bits) corrispondono a quattro caratteri di output. L'alfabeto non è arbitrario: evita i caratteri che differiscono tra EBCDIC e ASCII, evitando i caratteri di controllo, le virgolette e la barra rovesciata che richiederebbe l'escape nelle stringhe letterali C. La variante base64url sostituisce il segno più con il trattino e la barra con il carattere di sottolineatura per evitare caratteri riservati negli URL e nei nomi dei file. Entrambe le varianti sono ugualmente valide; RFC 4648 la sezione 2 specifica base64, la sezione 5 specifica base64url e un'applicazione deve indicare quale utilizza.
Il riempimento con caratteri uguali porta l'output a un multiplo di quattro caratteri. Se l'input è 1 byte (8 bits), l'output è composto da due caratteri più due segni di uguale. Se l'input è 2 bytes (16 bits), l'output è composto da tre caratteri più un segno di uguale. Se l'input è un multiplo di 3 bytes, non è necessaria alcuna spaziatura. Alcune applicazioni omettono il riempimento o consentono il riempimento mancante durante la decodifica; RFC 4648 la sezione 3.2 definisce la codifica canonica come sempre imbottita, ma la sezione 3.3 rileva che i decodificatori potrebbero accettare l'imbottitura mancante per compatibilità.
Gli alfabeti implementati da questo strumento: Base64 e Base64url standard; altre basi rimangono fuori dal suo campo di applicazione
La distinzione del riempimento è il motivo per cui le implementazioni non sono d'accordo: un decodificatore rigoroso rifiuta gli uguali mancanti, mentre uno indulgente lo accetta. RFC 4648 dice esplicitamente: il carattere pad uguale è in genere codificato in percentuale quando utilizzato negli URL, quindi se l'output base64url viene utilizzato direttamente in un parametro URL, il riempimento non è richiesto e deve essere omesso. Questa frase è uno dei motivi per cui la modalità URL-safe e l'omissione del riempimento sono spesso abbinate, sebbene siano scelte indipendenti. La sezione 5 (base64url) non vieta il riempimento; si limita a constatare la pratica comune.
Un chiamante che sceglie base64url deve decidere se è richiesto il riempimento per il sistema ricevente. I caratteri non alfabetici nell'input vengono gestiti in modo diverso dai diversi decodificatori. RFC 4648 sezione 3.1 afferma: Le implementazioni MUST rifiutano la codifica se contiene caratteri al di fuori dell'alfabeto di base. Tuttavia, la sezione 3.3 rileva che MIME Base64 (RFC 2045) consente interruzioni di riga per il ritorno a capo dei caratteri 76 e i decodificatori per MIME devono saltare gli spazi bianchi. RFC distingue tra decodifica rigorosa (rifiuta tutti i caratteri non alfabetici) e decodifica compatibile con MIME (salta gli spazi bianchi, rifiuta altri caratteri).
Imbottitura, caratteri non alfabetici e codifica canonica: le sezioni che spiegano la maggior parte dei disaccordi del decodificatore
Un'applicazione deve scegliere quale regola seguire; lo standard definisce entrambi. Base32 utilizza A-Z e 2-7 (32 caratteri in totale), codificando cinque byte di input (40 bits) in otto caratteri di output. Base32hex sostituisce 0-9 e a-v per i caratteri alfabetici, utile in contesti in cui sono preferite le lettere minuscole.
Base16 è esadecimale: 0-9 e a-f. Base32 e base32hex hanno le proprie regole di riempimento nelle sezioni 6 e 7 e RFC fornisce vettori di test separati per ciascun alfabeto. La maggior parte degli sviluppatori necessita solo di base64 e base64url; base32, base32hex e base16 sono inclusi in RFC per completezza e per applicazioni come i segreti TOTP (RFC 4226) e la codifica DNS.
Scelte applicative visibili in questa implementazione: ritorno a capo, rigorosa decodifica del testo e gestione degli errori
I vettori di test in RFC 4648 sono la verità fondamentale per verificare un'implementazione. La codifica delle stringhe f, fo, foo, foob, fooba e foobar produce un output base64 specifico: Zg==, Zm8=, Zm9v, Zm9vYg==, Zm9vYmE= e Zm9vYmFy. Un'implementazione che produce output diverso per queste stringhe non è corretta. RFC fornisce vettori di test equivalenti per base32, base32hex e base16. Lo strumento di codifica e decodifica Base64 include questi vettori in modo da poter verificare il suo output rispetto allo standard. Il ritorno a capo della riga è un problema di MIME, non di Base64.
RFC 2045 specifica 76 righe di caratteri; RFC 4648 sezione 3.1 rileva questo nel contesto di MIME ma non lo rende un requisito di base64 stesso. Alcune applicazioni vanno a capo con 64 caratteri (lo standard PEM originale); altri non si avvolgono affatto. Un rigoroso decodificatore RFC 4648 base64 opera solo sull'alfabeto e sul riempimento. Un decoder compatibile con MIME deve saltare le interruzioni di riga (CR, LF, CRLF). Un'applicazione che utilizza base64 al di fuori di MIME non deve aggiungere interruzioni di riga a meno che il sistema ricevente non le richieda; RFC non definisce il ritorno a capo della riga come parte di base64.
Esempio funzionante: i vettori di test di RFC: codifica i prefissi 'foobar' e controllali nel browser
La gestione degli spazi bianchi è un altro punto di variazione dell'implementazione. RFC 4648 dice che i decodificatori rigidi devono rifiutare i caratteri non alfabetici. MIME-wrapped base64 (RFC 2045 base64) consente lo spazio bianco per la formattazione. I due standard concordano su quali dovrebbero essere i byte di output ma differiscono su quale input è valido. La maggior parte delle implementazioni JavaScript scelgono la compatibilità MIME e saltano gli spazi bianchi; la regola rigorosa viene utilizzata raramente nei browser. Il codificatore e decodificatore Base64 accetta sia input contenenti spazi bianchi (MIME) sia input rigorosi, rendendo esplicita la distinzione. La decodifica canonica rispetto a quella permissiva è l'ultima grande variazione.
La decodifica canonica segue la sezione RFC 4648 3.2: rifiuta l'imbottitura non corretta, rifiuta l'imbottitura mancante, rifiuta i caratteri non alfabetici. La decodifica permissiva, utilizzata negli standard web (la specifica HTML la chiama perdonante-base64), aggiunge regole: ignora gli spazi bianchi, accetta il riempimento mancante, consente trattino e carattere di sottolineatura come equivalenti di barra più anche in modalità base64 standard. atob() di JavaScript è indulgente; un decoder RFC 4648 rigoroso è più rigoroso. Nessuno dei due è sbagliato; servono contesti diversi. Un'applicazione che legge i dati di un utente o della rete dovrebbe sapere quale regola si aspetta l'altra parte.
Cosa non copre: i documenti MIME e PEM stessi e le API specifiche della lingua
RFC lascia nove scelte all'applicazione: quale dei cinque alfabeti, se richiedere o consentire il riempimento, se richiedere o consentire spazi bianchi, se trattare il trattino basso come equivalente di una barra più, come segnalare errori, come gestire la fine dell'input, se accettare il riempimento mancante, quanti byte di output allocare e come segnalare un limite di dimensione. Queste scelte spiegano perché due implementazioni RFC 4648 possono non essere d'accordo sullo stesso input. Leggi il RFC una volta; controlla la tua implementazione rispetto ai suoi vettori di test; indica quali opzioni utilizza la tua applicazione; testare l'interoperabilità con il peer reale, non le ipotesi.
Comprendere RFC 4648 risolve la maggior parte delle controversie su Base64 perché il disaccordo di solito non riguarda RFC stesso ma su quali opzioni ha scelto ciascuna parte. RFC è abbastanza breve da poter essere letto interamente in un'ora. Lo standard definisce gli alfabeti, fornisce vettori di test e avverte dove devono decidere le implementazioni. Lo strumento di codifica e decodifica Base64 ti consente di sperimentare i vettori di test e vedere l'alfabeto standard in azione. La maggior parte dell'uso quotidiano di Base64 non richiede una conoscenza approfondita di RFC; ma quando si esegue il debug di mancate corrispondenze di codifica o si integra con un API sconosciuto, leggere lo standard una volta elimina le congetture.
Conclusione: leggi lo standard una volta: come il codificatore e decodificatore Base64 ti offre un modo rapido per controllare i vettori di test dell'alfabeto standard
RFC 4648 è il consolidamento di decenni di pratiche di codifica di base ad hoc in un'unica specifica leggibile. Non definisce quando utilizzare base64 (MIME, PEM, JWT, URI di dati, ecc., ciascuno con le proprie specifiche); definisce cos'è base64. Definendo cinque famiglie di codifica e annotando quali opzioni sono canoniche, RFC consente di verificare se un'implementazione è corretta. I vettori di test autorevoli sono il punto di partenza: se la tua implementazione codifica foobar e produce qualcosa di diverso da Zm9vYmFy, RFC dice che l'implementazione è sbagliata.
Utilizza tale autorità come punto di controllo di verifica: codifica ciascun vettore di test RFC, confronta i caratteri esatti e quindi decodifica il risultato per confermare che i byte originali ritornano invariati. Questo controllo basato su browser separa un errore di alfabeto o di riempimento da un problema altrove in un'integrazione, mantenendo lo standard stesso come riferimento anziché fare affidamento su un'etichetta di libreria.