Perché usiamo Base64?


276

Wikipedia dice

Gli schemi di codifica Base64 vengono comunemente utilizzati quando è necessario codificare i dati binari che devono essere archiviati e trasferiti su supporti progettati per gestire dati testuali. Questo per garantire che i dati rimangano intatti senza modifiche durante il trasporto.

Ma i dati non sono sempre archiviati / trasmessi in binario perché la memoria che le nostre macchine hanno archiviano binario e dipende solo da come li interpreti? Quindi, sia che codifichi lo schema di bit 010011010110000101101110come Manin ASCII o come TWFuin Base64, alla fine memorizzerai lo stesso schema di bit.

Se la codifica finale è in termini di zero e uno e ogni macchina e supporto può gestirli, che importanza ha se i dati sono rappresentati come ASCII o Base64?

Cosa significa "media progettati per gestire dati testuali"? Possono gestire binario => possono gestire qualsiasi cosa.


Grazie a tutti, penso di aver capito adesso.

Quando inviamo i dati, non possiamo essere sicuri che i dati vengano interpretati nello stesso formato in cui intendevamo. Quindi, inviamo dati codificati in un formato (come Base64) che entrambe le parti comprendono. In questo modo anche se mittente e destinatario interpretano le stesse cose in modo diverso, ma poiché concordano sul formato codificato, i dati non verranno interpretati in modo errato.

Da Mark Byers esempio

Se voglio inviare

Hello
world!

Un modo è inviarlo in formato ASCII

72 101 108 108 111 10 119 111 114 108 100 33

Ma il byte 10 potrebbe non essere interpretato correttamente come una nuova riga all'altra estremità. Quindi, usiamo un sottoinsieme di ASCII per codificarlo in questo modo

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

che a scapito di più dati trasferiti per la stessa quantità di informazioni garantisce che il destinatario possa decodificare i dati nel modo previsto, anche se il ricevitore ha interpretazioni diverse per il resto del set di caratteri.


6
Sfondo storico: i server di posta elettronica erano in precedenza ASCII a 7 bit. Molti di loro imposteranno il bit alto su 0, quindi è necessario inviare solo valori a 7 bit. Vedi en.wikipedia.org/wiki/Email#Content_encoding
Harold L

53
Usiamo base64 perché è più leggibile di Perl
Martin il

2
@Martin, stai scherzando. Perl è difficile da leggere, ma base64 è illeggibile.
Peter Long,

1
@Lazer La tua immagine è mancante
Mick,

2
@Lazer, "Ma il byte 10 potrebbe non essere interpretato correttamente come una nuova riga all'altra estremità." perché? le due parti hanno concordato ASCII e devono interpretarlo correttamente!
ProgramCpp

Risposte:


299

Il tuo primo errore è pensare che la codifica ASCII e la codifica Base64 siano intercambiabili. Non sono. Sono utilizzati per scopi diversi.

  • Quando si codifica il testo in ASCII, si inizia con una stringa di testo e lo si converte in una sequenza di byte.
  • Quando si codificano i dati in Base64, si inizia con una sequenza di byte e li si converte in una stringa di testo.

Per capire perché Base64 era necessario in primo luogo abbiamo bisogno di un po 'di storia dell'informatica.


I computer comunicano in binario - 0 e 1 - ma le persone in genere vogliono comunicare con dati di moduli più ricchi come testo o immagini. Per trasferire questi dati tra computer, è necessario prima codificarli in 0s e 1s, inviarli e quindi decodificarli di nuovo. Per prendere il testo come esempio, ci sono molti modi per eseguire questa codifica. Sarebbe molto più semplice se potessimo essere tutti d'accordo su una singola codifica, ma purtroppo non è così.

Inizialmente sono state create molte codifiche diverse (ad esempio il codice Baudot ) che utilizzavano un numero diverso di bit per carattere fino a quando alla fine ASCII è diventato uno standard con 7 bit per carattere. Tuttavia, la maggior parte dei computer memorizza i dati binari in byte costituiti da 8 bit ciascuno, pertanto ASCII non è adatto per il trasferimento di questo tipo di dati. Alcuni sistemi cancellerebbero persino il bit più significativo. Inoltre, la differenza nelle codifiche di fine linea tra i sistemi significa che talvolta sono stati modificati anche i caratteri ASCII 10 e 13.

Per risolvere questi problemi è stata introdotta la codifica Base64 . Ciò consente di codificare byte aribtrari in byte noti per essere sicuri da inviare senza essere danneggiati (caratteri alfanumerici ASCII e un paio di simboli). Lo svantaggio è che la codifica del messaggio utilizzando Base64 ne aumenta la lunghezza: ogni 3 byte di dati viene codificato in 4 caratteri ASCII.

Per inviare il testo in modo affidabile, è possibile prima codificare in byte utilizzando una codifica di testo di propria scelta (ad esempio UTF-8) e successivamente Base64 codificare i dati binari risultanti in una stringa di testo sicura da inviare codificata come ASCII. Il destinatario dovrà invertire questo processo per recuperare il messaggio originale. Ciò ovviamente richiede che il destinatario sappia quali codifiche sono state utilizzate e che spesso queste informazioni devono essere inviate separatamente.

Storicamente è stato utilizzato per codificare i dati binari nei messaggi di posta elettronica in cui il server di posta elettronica potrebbe modificare le terminazioni di riga. Un esempio più moderno è l'uso della codifica Base64 per incorporare i dati di immagine direttamente nel codice sorgente HTML . Qui è necessario codificare i dati per evitare che caratteri come '<' e '>' vengano interpretati come tag.


Ecco un esempio funzionante:

Desidero inviare un messaggio di testo con due righe:

Ciao
mondo!

Se lo invio come ASCII (o UTF-8) sarà simile al seguente:

72 101 108 108 111 10 119 111 114 108 100 33

Il byte 10 è danneggiato in alcuni sistemi, quindi possiamo basare 64 codificare questi byte come una stringa Base64:

SGVsbG8sCndvcmxkIQ ==

Che quando codificato utilizzando ASCII è simile al seguente:

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

Tutti i byte qui sono noti byte sicuri, quindi ci sono poche possibilità che qualsiasi sistema corrompa questo messaggio. Posso inviare questo invece del mio messaggio originale e lasciare che il destinatario inverta il processo per recuperare il messaggio originale.


4
"la maggior parte dei protocolli di comunicazione moderni non corromperà i dati", anche se ad esempio la posta elettronica potrebbe, con un agente di consegna che sostituisce la stringa di caratteri "\ nDa" con "\ n> Da" quando salva il messaggio in una cassetta postale. Oppure le intestazioni HTTP sono terminate a riga nuova senza alcun modo reversibile per sfuggire a nuove righe nei dati (la continuazione della linea si fonde con lo spazio bianco), quindi non è nemmeno possibile scaricare ASCII arbitrari in esse. base64 è meglio di solo 7-bit sicuro, è alfa-numerico-e - = + / sicuro.
Steve Jessop,

1
"Lo svantaggio è che la codifica del messaggio utilizzando Base64 ne aumenta la lunghezza - ogni 3 byte di dati viene codificato a 4 byte." Come aumenta a 4 byte? Non sarà comunque solo 3 * 8 = 24 bit?
Lazer,

4
@Lazer: no. Guarda il tuo esempio: "Man" è codificato in base 64 come "TWFu". 3 byte -> 4 byte. È perché l'input può essere uno qualsiasi dei 2 ^ 8 = 256 byte possibili, mentre l'output ne utilizza solo 2 ^ 6 = 64 (e =, per aiutare a indicare la lunghezza dei dati). 8 bit per quartetto di output vengono "sprecati", per evitare che l'output contenga caratteri "entusiasmanti", anche se l'input lo fa.
Steve Jessop,

3
Potrebbe essere utile riformulare "Quando si codificano i dati in Base64, si inizia con una sequenza di byte e li si converte in una stringa di testo" come "Quando si codificano i dati in Base64, si inizia con una sequenza di byte e li si converte in un sequenza di byte costituita solo da valori ASCII ". Una sequenza di byte costituita solo da caratteri ASCII è ciò che è richiesto da SMTP, motivo per cui Base64 (e quoted-printable) sono utilizzati come codifiche di trasferimento del contenuto. Eccellente panoramica!
ALEXintlsos,

1
Vorrei votare, ma ha 64 voti. Mi dispiace, questo è perfetto.
Jessé Catrinck,

61

Codifica di dati binari in XML

Supponiamo di voler incorporare un paio di immagini in un documento XML. Le immagini sono dati binari, mentre il documento XML è testo. Ma XML non è in grado di gestire dati binari incorporati. Quindi come lo fai?

Un'opzione è codificare le immagini in base64, trasformando i dati binari in testo che XML può gestire.

Invece di:

<images>
  <image name="Sally">{binary gibberish that breaks XML parsers}</image>
  <image name="Bobby">{binary gibberish that breaks XML parsers}</image>
</images>

tu fai:

<images>
  <image name="Sally" encoding="base64">j23894uaiAJSD3234kljasjkSD...</image>
  <image name="Bobby" encoding="base64">Ja3k23JKasil3452AsdfjlksKsasKD...</image>
</images>

E il parser XML sarà in grado di analizzare correttamente il documento XML ed estrarre i dati dell'immagine.


Questo potrebbe essere il modo in cui funziona il vecchio .mhtformato di Microsoft (file html + immagini in un singolo file).
Sridhar Sarnobat,

38

Perché non guardare alla RFC che attualmente definisce Base64 ?

La codifica di base dei dati viene utilizzata in molte situazioni per archiviare o trasferire i
dati in ambienti che, forse per motivi legacy, sono limitati ai dati US-ASCII [1]. La codifica di base può essere utilizzata anche in nuove applicazioni che non hanno restrizioni di legacy, semplicemente perché consente di manipolare oggetti con editor di testo.

In passato, diverse applicazioni avevano requisiti diversi e quindi a volte implementavano codifiche di base in modi leggermente diversi. Oggi, le specifiche del protocollo a volte utilizzano codifiche di base in generale e "base64" in particolare, senza una descrizione o un riferimento precisi. MIME (Multipurpose Internet Mail Extensions) [4] è spesso usato come riferimento per base64 senza considerare le conseguenze per il ritorno a capo o caratteri non alfabetici. Lo scopo di questa specifica è di stabilire considerazioni di alfabeto e codifica comuni. Si spera che ciò riduca l'ambiguità in altri documenti, portando a una migliore interoperabilità.

Base64 è stato originariamente concepito come un modo per consentire ai dati binari di essere allegati alle e-mail come parte delle estensioni di posta Internet multiuso.


26

Naturalmente anche i supporti progettati per i dati testuali sono binari, ma i supporti testuali spesso usano determinati valori binari per i caratteri di controllo. Inoltre, i supporti testuali possono rifiutare determinati valori binari come non testuali.

La codifica Base64 codifica i dati binari come valori che possono essere interpretati solo come testo nei supporti testuali ed è privo di caratteri speciali e / o caratteri di controllo, in modo che i dati vengano conservati anche attraverso i supporti testuali.


Quindi è come con Base64, principalmente sia l'origine che la destinazione interpretano i dati allo stesso modo, perché molto probabilmente interpreteranno questi 64 caratteri allo stesso modo, anche se interpretano i caratteri di controllo in modi diversi. È giusto?
Lazer,

6
Questi dati potrebbero persino essere distrutti durante il trasporto. Ad esempio, molti programmi FTP riscrivono le terminazioni di riga da 13,10 a 10 o viceversa se il sistema operativo del server e del client non corrispondono e il trasferimento è contrassegnato come modalità testo. FTP è solo il primo esempio che mi è venuto in mente, non è buono perché FTP supporta una modalità binaria.
Hendrik Brummermann,

@nhnb: Penso che FTP sia un ottimo esempio poiché mostra che la modalità testo non è adatta a cose che vogliono dati binari.
jamesdlin,

Che cos'è un supporto testuale?
Koray Tugay,

18

È più che il supporto convalida la codifica della stringa, quindi vogliamo garantire che i dati siano accettabili da un'applicazione di gestione (e non contengano una sequenza binaria che rappresenta EOL per esempio)

Immagina di voler inviare dati binari in un'e-mail con codifica UTF-8 - L'e-mail potrebbe non essere visualizzata correttamente se il flusso di uno e zeri crea una sequenza che non è valida Unicode nella codifica UTF-8.

Lo stesso tipo di cose accade negli URL quando vogliamo codificare caratteri non validi per un URL nell'URL stesso:

http://www.foo.com/hello amico mio -> http://www.foo.com/hello%20my%20friend

Questo perché vogliamo inviare uno spazio su un sistema che penserà che lo spazio sia maleodorante.

Tutto ciò che stiamo facendo è garantire che vi sia una mappatura 1-a-1 tra una sequenza nota di bit nota, accettabile e non dannosa con un'altra sequenza letterale di bit e che l'applicazione di gestione non distingua la codifica.

Nel tuo esempio, manpuò essere valido ASCII in prima forma; ma spesso potresti voler trasmettere valori binari casuali (ad es. invio di un'immagine in un'e-mail):

Versione MIME: 1.0
Descrizione
contenuto: Tipo di contenuto "Base64 encode of a.gif" : image / gif; name = "a.gif"
Codifica trasferimento
contenuto : Base64 Disposizione contenuto: allegato; filename = "a.gif"

Qui vediamo che un'immagine GIF è codificata in base64 come un pezzo di e-mail. Il client di posta elettronica legge le intestazioni e lo decodifica. A causa della codifica, possiamo essere certi che la GIF non contenga nulla che possa essere interpretato come protocollo ed evitiamo di inserire dati che SMTP o POP potrebbero trovare significativi.


1
È fantastico: questa spiegazione ha fatto clic. Non è per offuscare o comprimere i dati, ma semplicemente per evitare l'uso di sequenze speciali che possono essere interpretate come protocollo.
Patrick Michaelsen,

13

Base64 invece di sfuggire ai caratteri speciali

Ti darò un esempio molto diverso ma reale: scrivo codice javascript per essere eseguito in un browser. I tag HTML hanno valori ID, ma ci sono vincoli su quali caratteri sono validi in un ID.

Ma voglio che il mio ID si riferisca senza perdita di file ai miei file system. I file in realtà possono contenere ogni sorta di personaggi strani e meravigliosi da punti esclamativi, caratteri accentati, tilde, persino emoji! Non posso farlo:

<div id="/path/to/my_strangely_named_file!@().jpg">
    <img src="http://myserver.com/path/to/my_strangely_named_file!@().jpg">
    Here's a pic I took in Moscow.
</div>

Supponiamo di voler eseguire un codice come questo:

# ERROR
document.getElementById("/path/to/my_strangely_named_file!@().jpg");

Penso che questo codice fallirà quando eseguito.

Con Base64 posso fare riferimento a qualcosa di complicato senza preoccuparmi di quale lingua consente quali caratteri speciali e quali necessitano di essere salvati:

document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA");

A differenza dell'utilizzo di un MD5 o di qualche altra funzione di hashing, è possibile invertire la codifica per scoprire esattamente quali dati fossero effettivamente utili.

Vorrei sapere Base64 anni fa. Avrei evitato di strapparmi i capelli con ' encodeURIComponent' estr.replace(‘\n’,’\\n’)

Trasferimento SSH di testo:

Se stai cercando di trasferire dati complessi su ssh (ad esempio un dotfile in modo da poter ottenere le tue personalizzazioni della shell), buona fortuna farlo senza Base 64. Ecco come lo faresti con Base 64 (so che puoi usare SCP, ma ciò richiederebbe più comandi, il che complica i collegamenti dei tasti per l'invio in un server):


12

Un esempio di quando l'ho trovato conveniente è stato quando ho cercato di incorporare dati binari in XML . Alcuni dati binari venivano interpretati in modo errato dal parser SAX perché tali dati potevano essere letteralmente qualsiasi cosa, inclusi i caratteri speciali XML. Base64 codifica i dati sull'estremità trasmittente e decodifica sull'estremità ricevente risolto il problema.


1
+1 - ma questo non è affatto specifico per SAX. Succederebbe a qualsiasi parser XML, cioè DOM o XLINQ.
Billy ONeal,

1
@Billy: Sì, assolutamente. Mi è capitato di usare un parser SAX per quell'applicazione.
Bill the Lizard,

Motori diversi, ad esempio il parser SAX, potrebbero interpretare alcuni dei valori ASCII in modi diversi (caratteri di controllo diversi). Quindi, l'idea qui è di usare il sottoinsieme di ASCII che ha il significato comune universalmente. Destra?
Lazer,

1
@Lazer: giusto. I dati binari non codificati conterranno caratteri di controllo solo per caso quando si tenta di interpretarli come ASCII (che in questo caso non lo era).
Bill the Lizard,

10

La maggior parte dei computer memorizza i dati in formato binario a 8 bit, ma questo non è un requisito. Alcune macchine e supporti di trasmissione possono gestire solo 7 bit (o forse anche meno) alla volta. Un tale mezzo interpreterebbe il flusso in multipli di 7 bit, quindi se dovessi inviare dati a 8 bit, non riceverai ciò che ti aspetti dall'altra parte. Base-64 è solo un modo per risolvere questo problema: si codifica l'input in un formato a 6 bit, lo si invia sul supporto e si decodifica in formato a 8 bit alla fine della ricezione.


3
Perché è un problema se il flusso si interrompe dopo 7 bit. Alla fine, l'altra macchina avrà tutti i dati ricevuti sul flusso, può quindi scegliere il formato a 8 bit per visualizzarlo? Cosa c'è che non va nella mia mente!
Mallaudin,

6

Oltre alle altre (piuttosto lunghe) risposte: anche ignorando i vecchi sistemi che supportano solo ASCII a 7 bit, i problemi di base con la fornitura di dati binari in modalità testo sono:

  • Le nuove righe vengono in genere trasformate in modalità testo.
  • Bisogna stare attenti a non considerare un byte NUL come la fine di una stringa di testo, il che è fin troppo facile da fare in qualsiasi programma con discendenza C.

Esistono anche caratteri di controllo come ^ C, ^ D e ^ Z che vengono interpretati come end-of-file su alcune piattaforme.
dan04,

5

Cosa significa "media progettati per gestire dati testuali"?

Che quei protocolli fossero progettati per gestire il testo (spesso solo in inglese ) anziché i dati binari (come le immagini .png e .jpg).

Possono gestire binario => possono gestire qualsiasi cosa.

Ma il contrario non è vero. Un protocollo progettato per rappresentare il testo può trattare erroneamente i dati binari che contengono:

  • I byte 0x0A e 0x0D, utilizzati per i finali di linea, che differiscono per piattaforma.
  • Altri caratteri di controllo come 0x00 (NULL = terminatore stringa C), 0x03 (END OF TEXT), 0x04 (END OF TRANSMISSION) o 0x1A (fine del file DOS) che possono segnalare prematuramente la fine dei dati.
  • Byte superiori a 0x7F (se il protocollo è stato progettato per ASCII).
  • Sequenze di byte non valide UTF-8.

Quindi non puoi semplicemente inviare dati binari su un protocollo testuale. Sei limitato ai byte che rappresentano i caratteri ASCII non di controllo non spaziali, di cui ce ne sono 94. Il motivo per cui è stato scelto Base 64 è che è più veloce lavorare con potenze di due, e 64 è il più grande che funziona .

Una domanda però. In che modo i sistemi non sono ancora d'accordo su una tecnica di codifica comune come il così comune UTF-8?

Sul Web, almeno, ce l'hanno per lo più. La maggior parte dei siti utilizza UTF-8 .

Il problema in Occidente è che ci sono molti vecchi software che suppongono che 1 byte = 1 carattere e non possano funzionare con UTF-8.

Il problema in Oriente è il loro attaccamento a codifiche come GB2312 e Shift_JIS.

E il fatto che Microsoft sembra non aver ancora superato la scelta della codifica UTF errata. Se si desidera utilizzare l'API di Windows o la libreria di runtime di Microsoft C, si è limitati a UTF-16 o alla codifica "ANSI" della locale. Questo rende doloroso usare UTF-8 perché devi convertirlo continuamente.


5

Perché / Come si usa la codifica Base64?

Base64 è uno degli schemi di codifica da binario a testo con un'efficienza del 75%. Viene utilizzato in modo che i dati binari tipici (come le immagini) possano essere inviati in modo sicuro su canali legacy "non a 8 bit". Nelle reti di posta elettronica precedenti (fino agli inizi degli anni '90), la maggior parte dei messaggi di posta elettronica erano in chiaro nel set di caratteri US-ASCII a 7 bit. Tanti standard di protocollo di comunicazione precoci sono stati progettati per funzionare su "collegamenti di comunicazione a 7 bit" non puliti a 8 bit ". L'efficienza dello schema è il rapporto tra il numero di bit nell'ingresso e il numero di bit nell'uscita codificata. Hexadecimal (Base16) è anche uno degli schemi di codifica da binario a testo con un'efficienza del 50%.

Passaggi di codifica Base64 (semplificati):

  1. I dati binari sono organizzati in blocchi continui di 24 bit (3 byte) ciascuno.
  2. Ogni blocco di 24 bit è raggruppato in quattro parti di 6 bit ciascuna.
  3. Ogni gruppo a 6 bit viene convertito nei corrispondenti valori dei caratteri Base64, ovvero la codifica Base64 converte tre ottetti in quattro caratteri codificati. Il rapporto tra byte di output e byte di input è 4: 3 (sovraccarico del 33%).
  4. È interessante notare che gli stessi personaggi saranno codificati in modo diverso a seconda della loro posizione all'interno del gruppo di tre ottetti che è codificato per produrre i quattro personaggi.
  5. Il destinatario dovrà invertire questo processo per recuperare il messaggio originale.

3

Cosa significa "media progettati per gestire dati testuali"?

Ai tempi in cui ASCII governava il mondo che si occupava di valori non ASCII era un mal di testa. Le persone hanno saltato attraverso tutti i tipi di cerchi per farli trasferire sul filo senza perdere informazioni.


3
In realtà, ai tempi nostri, ASCII non era nemmeno usato dappertutto. Molti protocolli avevano una modalità testuale e binaria separata per il trasferimento dei dati, sfortunatamente la posta elettronica allora non lo era. La modalità testo è necessaria proprio perché nessuna codifica di un singolo testo governava il mondo, non ASCII; ogni rete di computer ha la propria codifica preferita, quindi ci sono gateway il cui compito è convertire il testo scambiato nella codifica locale in modo che una società giapponese possa inviare e-mail a un consulente aziendale americano senza mojibake. Questa conversione, ovviamente, è indesiderabile quando si inviano dati binari.
Lie Ryan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.