Por que usamos o Base64?

276

Wikipedia diz

Os esquemas de codificação Base64 são comumente usados ​​quando há a necessidade de codificar dados binários que precisam ser armazenados e transferidos por mídia projetada para lidar com dados de texto. Isso é para garantir que os dados permaneçam intactos sem modificação durante o transporte.

Mas não é que os dados sejam sempre armazenados / transmitidos em binário porque a memória que nossas máquinas armazenam é binária e depende apenas de como você os interpreta? Portanto, se você codifica o padrão de bits 010011010110000101101110como Manem ASCII ou como TWFuem Base64, acabará armazenando o mesmo padrão de bits.

Se a codificação final é em zeros e uns e todas as máquinas e mídias podem lidar com eles, como importa se os dados são representados como ASCII ou Base64?

O que significa "mídia projetada para lidar com dados de texto"? Eles podem lidar com binário => eles podem lidar com qualquer coisa.


Obrigado a todos, acho que entendo agora.

Quando enviamos dados, não podemos ter certeza de que os dados serão interpretados no mesmo formato que pretendemos. Portanto, enviamos dados codificados em algum formato (como Base64) que ambas as partes entendem. Dessa forma, mesmo que o remetente e o destinatário interpretem as mesmas coisas de maneira diferente, mas como eles concordam com o formato codificado, os dados não serão interpretados incorretamente.

Do exemplo de Mark Byers

Se eu quiser enviar

Hello
world!

Uma maneira é enviá-lo em ASCII como

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

Mas o byte 10 pode não ser interpretado corretamente como uma nova linha na outra extremidade. Então, usamos um subconjunto de ASCII para codificá-lo assim

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

que, ao custo de mais dados transferidos para a mesma quantidade de informações, garante que o receptor possa decodificar os dados da maneira pretendida, mesmo que o receptor tenha interpretações diferentes para o restante do conjunto de caracteres.

lazer
fonte
6
Antecedentes históricos: os servidores de email costumavam ser ASCII de 7 bits. Muitos deles definiriam o bit alto como 0, então você tinha que enviar apenas valores de 7 bits. Veja en.wikipedia.org/wiki/Email#Content_encoding
Harold L
53
Usamos base64 porque é mais legível do que Perl
Martin
2
@ Martin, você está brincando. Perl é difícil de ler, mas base64 é ilegível.
Peter Long
1
@Lazer Sua imagem está faltando
Mick
2
@Lazer, "Mas o byte 10 pode não ser interpretado corretamente como uma nova linha na outra extremidade." porque? as duas partes concordaram com o ASCII e devem interpretá-lo corretamente!
precisa saber é o seguinte

Respostas:

299

Seu primeiro erro é pensar que as codificações ASCII e Base64 são intercambiáveis. Eles não são. Eles são usados ​​para diferentes propósitos.

  • Ao codificar texto em ASCII, você inicia com uma sequência de texto e a converte em uma sequência de bytes.
  • Ao codificar dados no Base64, você inicia com uma sequência de bytes e os converte em uma sequência de texto.

Para entender por que o Base64 era necessário em primeiro lugar, precisamos de um pouco de história da computação.


Os computadores se comunicam em binário - 0s e 1s -, mas as pessoas geralmente desejam se comunicar com dados de formulários mais avançados, como texto ou imagens. Para transferir esses dados entre computadores, é necessário primeiro codificar em 0s e 1s, enviar e depois decodificar novamente. Para tomar o texto como exemplo - existem muitas maneiras diferentes de executar essa codificação. Seria muito mais simples se todos pudéssemos concordar com uma única codificação, mas infelizmente esse não é o caso.

Originalmente, várias codificações diferentes foram criadas (por exemplo, código Baudot ), que usavam um número diferente de bits por caractere até que o ASCII se tornasse um padrão com 7 bits por caractere. No entanto, a maioria dos computadores armazena dados binários em bytes que consistem em 8 bits cada, portanto o ASCII é inadequado para transferir esse tipo de dados. Alguns sistemas até apagariam o bit mais significativo. Além disso, a diferença nas codificações de final de linha entre os sistemas significa que os caracteres ASCII 10 e 13 também foram modificados às vezes.

Para resolver esses problemas, a codificação Base64 foi introduzida. Isso permite que você codifique bytes arbitrários para bytes que são seguros enviar sem serem corrompidos (caracteres alfanuméricos ASCII e alguns símbolos). A desvantagem é que a codificação da mensagem usando Base64 aumenta seu comprimento - a cada 3 bytes de dados são codificados para 4 caracteres ASCII.

Para enviar texto de maneira confiável, você pode primeiro codificar para bytes usando uma codificação de texto de sua escolha (por exemplo, UTF-8) e depois Base64 codifica os dados binários resultantes em uma sequência de texto que é segura para enviar codificada como ASCII. O receptor terá que reverter esse processo para recuperar a mensagem original. É claro que isso requer que o receptor saiba quais codificações foram usadas e essas informações geralmente precisam ser enviadas separadamente.

Historicamente, tem sido usado para codificar dados binários em mensagens de email em que o servidor de email pode modificar as terminações de linha. Um exemplo mais moderno é o uso da codificação Base64 para incorporar dados de imagem diretamente no código-fonte HTML . Aqui é necessário codificar os dados para evitar que caracteres como '<' e '>' sejam interpretados como tags.


Aqui está um exemplo de trabalho:

Desejo enviar uma mensagem de texto com duas linhas:

Olá
mundo!

Se eu enviá-lo como ASCII (ou UTF-8), ficará assim:

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

O byte 10 está corrompido em alguns sistemas, então podemos codificar com base 64 esses bytes como uma string Base64:

SGVsbG8sCndvcmxkIQ ==

Que quando codificado usando ASCII se parece com isso:

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

Todos os bytes aqui são bytes seguros conhecidos, portanto, há muito pouca chance de que qualquer sistema corrompa essa mensagem. Posso enviar isso em vez da minha mensagem original e deixar o destinatário reverter o processo para recuperar a mensagem original.

Mark Byers
fonte
4
"a maioria dos protocolos de comunicação modernos não corrompe os dados" - embora, por exemplo, o e-mail possa, com um agente de entrega substituindo a sequência de caracteres "\ nDe" por "\ n> De" quando salva a mensagem em uma caixa de correio. Ou os cabeçalhos HTTP são encerrados com nova linha, sem uma maneira reversível de escapar de novas linhas nos dados (a continuação da linha confunde espaço em branco); portanto, você também não pode despejar ASCII arbitrário neles. base64 é melhor do que apenas 7 bits de segurança, é alfanumérico e - = + / seguro.
Steve Jessop
1
"A desvantagem é que a codificação da mensagem usando o Base64 aumenta seu comprimento - a cada 3 bytes de dados são codificados para 4 bytes". Como aumenta para 4 bytes? Ainda não será de 3 * 8 = apenas 24 bits?
Lazer
4
@Lazer: não. Veja seu próprio exemplo - "Man" é codificado em base 64 como "TWFu". 3 bytes -> 4 bytes. É porque a entrada pode ter qualquer um dos 2 ^ 8 = 256 bytes possíveis, enquanto a saída usa apenas 2 ^ 6 = 64 deles (e =, para ajudar a indicar o comprimento dos dados). 8 bits por quarteto de saída são "desperdiçados", a fim de impedir que a saída contenha caracteres "emocionantes", mesmo que a entrada o faça.
Steve Jessop
3
Pode ser útil redefinir "Ao codificar dados no Base64, você inicia com uma sequência de bytes e os converte em uma sequência de texto" como "Ao codificar dados no Base64, você inicia com uma sequência de bytes e os converte em um sequência de bytes que consiste apenas em valores ASCII ". Uma sequência de bytes consistindo apenas em caracteres ASCII é o que o SMTP exige, e é por isso que Base64 (e impressão entre aspas) são usadas como codificações de transferência de conteúdo. Excelente visão geral!
28413 ALEXintlsos
1
Eu votaria, mas tem 64 votos. Desculpe, isso é perfeito.
Jessé Catrinck 07/01
61

Codificando Dados Binários em XML

Suponha que você queira incorporar algumas imagens em um documento XML. As imagens são dados binários, enquanto o documento XML é texto. Mas o XML não pode manipular dados binários incorporados. Então como você faz isso?

Uma opção é codificar as imagens na base64, transformando os dados binários em texto que o XML pode manipular.

Ao invés de:

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

Você faz:

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

E o analisador XML poderá analisar o documento XML corretamente e extrair os dados da imagem.

yfeldblum
fonte
Pode ser assim que o .mhtformato antigo da Microsoft funciona (arquivo html + imagens em um único arquivo).
Sridhar Sarnobat
38

Por que não olhar para o RFC que atualmente define o Base64 ?

A codificação base de dados é usada em muitas situações para armazenar ou transferir
dados em ambientes que, talvez por motivos herdados, sejam restritos aos dados US-ASCII [1]. A codificação base também pode ser usada em novos aplicativos que não têm restrições herdadas, simplesmente porque torna possível manipular objetos com editores de texto.

No passado, aplicativos diferentes tinham requisitos diferentes e, portanto, algumas vezes implementavam codificações de base de maneiras ligeiramente diferentes. Hoje, as especificações de protocolo às vezes usam codificações de base em geral e "base64" em particular, sem uma descrição ou referência precisa. MIME (Multipurpose Internet Mail Extensions) [4] é frequentemente usada como referência para base64 sem considerar as conseqüências para quebra de linha ou caracteres que não sejam do alfabeto. O objetivo desta especificação é estabelecer considerações comuns sobre alfabeto e codificação. Esperamos que isso reduza a ambiguidade em outros documentos, levando a uma melhor interoperabilidade.

O Base64 foi originalmente desenvolvido como uma maneira de permitir que dados binários sejam anexados a emails como parte das Extensões de Correio da Internet com Múltiplos Propósitos.

Billy ONeal
fonte
26

A mídia projetada para dados textuais também é, obviamente, binária, mas a mídia textual geralmente usa certos valores binários para caracteres de controle. Além disso, a mídia textual pode rejeitar certos valores binários como não texto.

A codificação Base64 codifica dados binários como valores que só podem ser interpretados como texto na mídia textual e está livre de caracteres especiais e / ou caracteres de controle, para que os dados sejam preservados também na mídia textual.

Håvard S
fonte
Assim, como no Base64, principalmente a origem e o destino interpretam os dados da mesma maneira, porque provavelmente interpretarão esses 64 caracteres da mesma maneira, mesmo que interpretem os caracteres de controle de maneiras diferentes. Isso está certo?
Lazer
6
Esses dados podem até ser destruídos em trânsito. Por exemplo, muitos programas de FTP reescrevem as terminações de linha de 13,10 a 10 ou via versa se o sistema operacional do servidor e do cliente não corresponder e a transferência for sinalizada como modo de texto. O FTP é apenas o primeiro exemplo que me veio à cabeça, não é bom porque o FTP suporta um modo binário.
Hendrik Brummermann
@ nhnb: Eu acho que o FTP é um bom exemplo, pois mostra que o modo de texto não é adequado para coisas que desejam dados binários.
Jamesdlin
O que é uma mídia textual?
Koray Tugay
18

Além disso, a mídia valida a codificação de string, portanto, queremos garantir que os dados sejam aceitáveis ​​por um aplicativo de manipulação (e não contenham uma sequência binária representando EOL, por exemplo)

Imagine que você deseja enviar dados binários em um email com codificação UTF-8 - O email pode não ser exibido corretamente se o fluxo de uns e zeros criar uma sequência que não é Unicode válida na codificação UTF-8.

O mesmo tipo de coisa acontece nos URLs quando queremos codificar caracteres não válidos para um URL no próprio URL:

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

Isso ocorre porque queremos enviar um espaço através de um sistema que achará que o espaço está fedido.

Tudo o que estamos fazendo é garantir que haja um mapeamento 1 para 1 entre uma sequência de bits boa, aceitável e não prejudicial conhecida para outra sequência literal de bits, e que o aplicativo de manipulação não distinga a codificação.

No seu exemplo, manpode ser ASCII válido na primeira forma; mas geralmente você pode transmitir valores binários aleatórios (por exemplo, enviar uma imagem em um email):

Versão MIME: 1.0
Descrição do conteúdo: "Codificação Base64 de a.gif"
Tipo de Conteúdo: image / gif; name = "a.gif"
Codificação de transferência de
conteúdo : Base64 Disposição de conteúdo: anexo; filename = "a.gif"

Aqui vemos que uma imagem GIF é codificada em base64 como parte de um email. O cliente de email lê os cabeçalhos e os decodifica. Devido à codificação, podemos ter certeza de que o GIF não contém nada que possa ser interpretado como protocolo e evitamos inserir dados que SMTP ou POP possam achar significantes.

Aiden Bell
fonte
1
Isso é incrível - essa explicação fez clique. Não é para ofuscar ou compactar dados, mas simplesmente para evitar o uso de seqüências especiais que podem ser interpretadas como protocolo.
Patrick Michaelsen
13

Base64 em vez de escapar de caracteres especiais

Vou dar um exemplo muito diferente, mas real: escrevo código javascript para ser executado em um navegador. As tags HTML têm valores de ID, mas há restrições sobre quais caracteres são válidos em um ID.

Mas quero que meu ID se refira sem perdas a arquivos no meu sistema de arquivos. Na realidade, os arquivos podem ter todos os tipos de caracteres estranhos e maravilhosos, como pontos de exclamação, caracteres acentuados, til e até emoji! Eu não posso fazer isto:

<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>

Suponha que eu queira executar algum código como este:

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

Eu acho que esse código falhará quando executado.

Com o Base64, posso me referir a algo complicado sem me preocupar com qual idioma permite quais caracteres especiais e quais precisam ser escapados:

document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA");

Ao contrário do uso de um MD5 ou de alguma outra função de hash, você pode reverter a codificação para descobrir exatamente quais eram os dados realmente úteis.

Eu gostaria de saber sobre a Base64 anos atrás. Eu teria evitado arrancar meu cabelo com ' encodeURIComponent' estr.replace(‘\n’,’\\n’)

Transferência SSH de texto:

Se você estiver tentando passar dados complexos pelo ssh (por exemplo, um arquivo de ponto para obter personalizações do shell), boa sorte sem o Base 64. É assim que você faria com o Base 64 (eu sei que você pode usar o SCP, mas seriam necessários vários comandos - o que complica as ligações de teclas para o sshing em um servidor):

Sridhar Sarnobat
fonte
12

Um exemplo de quando achei conveniente foi ao tentar incorporar dados binários em XML . Alguns dos dados binários estavam sendo mal interpretados pelo analisador SAX, porque esses dados podem ser literalmente qualquer coisa, incluindo caracteres especiais XML. A Base64, que codifica os dados na extremidade de transmissão e decodifica-os na extremidade de recebimento, corrigiu esse problema.

Bill the Lizard
fonte
1
+1 - mas isso não é de forma alguma específico para SAX. Isso aconteceria com qualquer analisador XML, ou seja, DOM ou XLINQ.
Billy ONeal
1
@ Billy: Sim, com certeza. Acabei de usar um analisador SAX para esse aplicativo.
Bill the Lizard
Mecanismos diferentes, por exemplo, o analisador SAX podem interpretar alguns dos valores ASCII de maneiras diferentes (caracteres de controle diferentes). Portanto, a idéia aqui é usar o subconjunto de ASCII que tem o significado comum universalmente. Certo?
Lazer
1
@Lazer: Certo. Os dados binários não codificados terão caracteres de controle apenas por acaso, quando você tentar interpretá-los como ASCII (que, nesse caso, não era).
Bill o Lagarto
10

A maioria dos computadores armazena dados no formato binário de 8 bits, mas isso não é um requisito. Algumas máquinas e meios de transmissão podem lidar apenas com 7 bits (ou talvez até menos) por vez. Esse meio interpretaria o fluxo em múltiplos de 7 bits; portanto, se você enviar dados de 8 bits, não receberá o que espera do outro lado. A Base-64 é apenas uma maneira de resolver esse problema: você codifica a entrada em um formato de 6 bits, envia-a pela mídia e a decodifica de volta para o formato de 8 bits na extremidade receptora.

Casablanca
fonte
3
Por que é um problema se o fluxo interrompe após 7 bits. No final, a outra máquina terá todos os dados recebidos no fluxo e poderá escolher o formato de 8 bits para exibi-lo. O que há de errado com minha mente!
Mallaudin
6

Além das outras respostas (um tanto demoradas): mesmo ignorando sistemas antigos que suportam apenas ASCII de 7 bits, os problemas básicos do fornecimento de dados binários no modo de texto são:

  • As novas linhas geralmente são transformadas no modo de texto.
  • É preciso ter cuidado para não tratar um byte NUL como o final de uma sequência de texto, o que é muito fácil de executar em qualquer programa com linhagem C.
jamesdlin
fonte
Também existem caracteres de controle como ^ C, ^ D e ^ Z que são interpretados como fim de arquivo em algumas plataformas.
precisa saber é o seguinte
5

O que significa "mídia projetada para lidar com dados de texto"?

Que esses protocolos foram projetados para manipular texto (geralmente, apenas texto em inglês ) em vez de dados binários (como imagens .png e .jpg).

Eles podem lidar com binário => eles podem lidar com qualquer coisa.

Mas o inverso não é verdadeiro. Um protocolo projetado para representar texto pode tratar indevidamente dados binários que contêm:

  • Os bytes 0x0A e 0x0D, usados ​​para terminações de linha, que diferem por plataforma.
  • Outros caracteres de controle como 0x00 (NULL = C terminador de seqüência de caracteres), 0x03 (FIM DO TEXTO), 0x04 (FIM DA TRANSMISSÃO) ou 0x1A (fim do arquivo do DOS) que podem sinalizar prematuramente o final dos dados.
  • Bytes acima de 0x7F (se o protocolo foi projetado para ASCII).
  • Sequências de bytes que são UTF-8 inválidas.

Portanto, você não pode simplesmente enviar dados binários através de um protocolo baseado em texto. Você está limitado aos bytes que representam os caracteres ASCII sem espaço e sem controle, dos quais existem 94. A razão pela qual a Base 64 foi escolhida foi o fato de ser mais rápido trabalhar com potências de dois e 64 é o maior que funciona. .

Uma pergunta, porém. Como os sistemas ainda não concordam com uma técnica de codificação comum como a tão comum UTF-8?

Na Web, pelo menos, eles têm. A maioria dos sites usa UTF-8 .

O problema no Ocidente é que existem muitos softwares antigos que atribuem esse byte = 1 caractere e não podem funcionar com o UTF-8.

O problema no Oriente é o seu anexo a codificações como GB2312 e Shift_JIS.

E o fato de a Microsoft ainda não ter superado a escolha da codificação UTF errada. Se você deseja usar a API do Windows ou a biblioteca de tempo de execução do Microsoft C, você está limitado à codificação UTF-16 ou "ANSI" da localidade. Isso torna doloroso o uso de UTF-8, porque você precisa converter o tempo todo.

dan04
fonte
5

Por que / como usamos a codificação Base64?

Base64 é um dos esquemas de codificação de binário para texto com 75% de eficiência. É usado para que dados binários típicos (como imagens) possam ser enviados com segurança por canais "não limpos em 8 bits" herdados. Nas redes de email anteriores (até o início dos anos 90), a maioria das mensagens de email era texto sem formatação no conjunto de caracteres US-ASCII de 7 bits. Muitos padrões iniciais de protocolo de comunicação foram projetados para funcionar com links de comunicação de "7 bits", não limpos de 8 bits ". A eficiência do esquema é a razão entre o número de bits na entrada e o número de bits na saída codificada. Hexadecimal (Base16) também é um dos esquemas de codificação de binário para texto com 50% de eficiência.

Etapas de codificação Base64 (simplificadas):

  1. Os dados binários são organizados em blocos contínuos de 24 bits (3 bytes) cada.
  2. Cada pedaço de 24 bits é agrupado em quatro partes de 6 bits cada.
  3. Cada grupo de 6 bits é convertido em seus valores correspondentes de caracteres Base64, ou seja, a codificação Base64 converte três octetos em quatro caracteres codificados. A proporção de bytes de saída para bytes de entrada é de 4: 3 (sobrecarga de 33%).
  4. Curiosamente, os mesmos caracteres serão codificados de maneira diferente, dependendo de sua posição no grupo de três octetos, que é codificado para produzir os quatro caracteres.
  5. O receptor terá que reverter esse processo para recuperar a mensagem original.
Mushtaq Hussain
fonte
3

O que significa "mídia projetada para lidar com dados de texto"?

No dia em que a ASCII governava o mundo, lidar com valores não-ASCII era uma dor de cabeça. As pessoas pularam todos os tipos de argolas para transferi-las pela rede sem perder informações.

dirkgently
fonte
3
Na verdade, antigamente, o ASCII nem era usado em todos os lugares. Muitos protocolos tinham um modo de texto e um modo binário separados para transferir dados, infelizmente o e-mail não era naquela época. O modo de texto é necessário precisamente porque nenhuma codificação de texto única governava o mundo, não o ASCII; toda rede de computadores tem sua própria codificação favorita; portanto, existem gateways cuja tarefa é converter o texto trocado na codificação local, para que uma empresa japonesa possa enviar e-mail para um consultor de negócios americano sem mojibake. Essa conversão, obviamente, é indesejável ao enviar dados binários.
Lie Ryan