Codificador e decodificador Base64

Nos dois sentidos, seguro para Unicode, com alfabeto URL-safe quando precisar.

Para que serve

O Base64 resolve um problema: tem bytes arbitrários e um canal que só transporta texto imprimível. Cabeçalhos de correio, campos de texto em JSON, URLs, atributos de HTML e boa parte da infra-estrutura mais antiga estatelam-se perante binário em bruto. O Base64 mapeia cada três bytes em quatro caracteres retirados de um alfabeto de 64 símbolos que sobrevive a tudo isso.

É esse o propósito, todo ele. Não é compressão — a saída fica um terço maior. Não é cifra — não há chave nenhuma. É uma codificação de transporte, e todas as propriedades que lhe atribuem por engano nascem de confundir «não consigo ler isto» com «isto está protegido».

Onde o vai encontrar

  • JWT. Os três segmentos, no alfabeto seguro para URL e sem enchimento.
  • Autenticação básica de HTTP. O Authorization: Basic é apenas user:password codificado em Base64 — e é exactamente por isso que a autenticação básica sobre HTTP simples equivale a enviar a palavra-passe às claras.
  • Data URI. O data:image/png;base64,... embute um ficheiro directamente em HTML ou CSS.
  • Certificados e chaves PEM. As linhas entre -----BEGIN----- e -----END----- são DER codificado em Base64.
  • Anexos de correio. O SMTP é um protocolo de texto; o MIME usa Base64 para transportar tudo o que não o seja.

A armadilha do Unicode

O navegador dá-lhe btoa e atob, e são uma armadilha. Ambas trabalham sobre bytes representados como texto, portanto btoa lança erro em qualquer carácter acima de U+00FF. Experimente com um emoji e recebe InvalidCharacterError.

A solução é converter primeiro para bytes UTF-8, que é o que esta página faz:

// Encode any string safely
const bytes = new TextEncoder().encode(text);
const b64 = btoa(String.fromCharCode(...bytes));

// Decode back
const binary = atob(b64);
const out = new TextDecoder().decode(
  Uint8Array.from(binary, c => c.charCodeAt(0))
);

Uma ressalva sobre a linha de codificação: espalhar um array grande dentro de String.fromCharCode estoira a pilha de chamadas algures perto dos cem mil elementos. Para coisas grandes, percorra por blocos — esta página fá-lo, e é por isso que aguenta uma colagem de vários megabytes sem cair.

Os dois alfabetos

Padrão (RFC 4648 §4)Seguro para URL (§5)
Índice 62+-
Índice 63/_
Enchimento=, obrigatórioNormalmente omitido
Usado porMIME, PEM, autenticação básicaJWT, URLs, nomes de ficheiro

O enchimento é a parte que dá problemas. A sua única função é tornar o comprimento múltiplo de quatro, e um descodificador consegue sempre deduzir quanto falta — por isso a variante segura para URL dispensa-o. Os descodificadores estritos rejeitam então o resultado, e é por isso que um segmento de JWT colado noutra ferramenta falha tantas vezes. O descodificador aqui repõe o enchimento sozinho.

Onde é mal usado

Como o Base64 não se lê à primeira vista, usa-se como se fosse um segredo. Vale a pena nomear os casos concretos:

  • Base64 como armazenamento de palavras-passe. Isto é texto simples com uma fantasia vestida. As palavras-passe precisam de um resumo lento e de sentido único — bcrypt, scrypt, Argon2.
  • Base64 na carga de um JWT, como se fosse privada. A carga é legível por quem tiver o token, incluindo o próprio utilizador. Nunca lá ponha nada que não lhe mostrasse.
  • Base64 para passar dados à socapa por um filtro. Resulta, por pouco tempo, e qualquer analisador que se preze descodifica-o na mesma.

A regra que cobre os três casos: se a segurança de alguma coisa depende de quem lê não a descodificar, ela não tem segurança nenhuma.

Relacionado

O descodificador de JWT separa um token e analisa os dois segmentos num só passo. Se se trata de escapar texto que vai para um URL em vez de codificar bytes, a codificação percentual é a coisa diferente que provavelmente quer. E se o que descodificou for afinal JSON, o formatador trata de o arrumar.

Perguntas sobre Base64

Base64 é cifra?

Não, e convém dizê-lo sem rodeios porque esta confusão provoca incidentes a sério. Base64 é uma codificação reversível sem chave e sem segredo — quem tem a cadeia de caracteres tem os dados, e descodificá-la leva uma linha de código. Existe para fazer passar bytes por canais que só transportam texto imprimível, não para esconder seja o que for. Guardar uma palavra-passe codificada em Base64 é guardá-la em texto simples com um passo a mais.

Porque é que tantas ferramentas Base64 falham com emojis ou acentos?

Porque a função btoa do navegador trabalha com bytes e não com caracteres, e lança erro em tudo acima de U+00FF. As ferramentas que a chamam directamente falham no é, no 日本語 e em todos os emojis. Esta página codifica primeiro para bytes UTF-8 e descodifica da mesma maneira, por isso a ida e volta é limpa para qualquer texto que consiga escrever.

O que é o Base64 seguro para URL?

O alfabeto padrão inclui + e /, que têm ambos significado num URL, e o enchimento com =, que também tem. A variante segura para URL definida no RFC 4648 troca - por + e _ por /, e costuma dispensar o enchimento. É a que os JWT usam nos três segmentos, e é por isso que um segmento de JWT colado num descodificador normal falha muitas vezes até se repor o enchimento. O descodificador aqui aceita qualquer um dos alfabetos, com ou sem enchimento.

Porque é que a cadeia codificada é maior do que aquilo que introduzi?

Cerca de um terço maior, sempre. O Base64 representa três bytes de entrada como quatro caracteres imprimíveis, portanto a saída fica a 4/3 do tamanho antes do enchimento. É o preço de usar apenas caracteres que sobrevivem a sistemas incapazes de transportar bytes arbitrários. É também por isso que embutir imagens como data: URI no CSS deixa a folha de estilos visivelmente maior do que eram os ficheiros de imagem.

Descodifiquei uma coisa e saiu um amontoado sem sentido. O que aconteceu?

O mais provável é que os bytes não sejam texto. O Base64 codifica binário arbitrário — uma imagem, um certificado, um arquivo comprimido — e transformá-los numa cadeia de caracteres produz disparate, porque não há ali texto para recuperar. Esta página diz-lho explicitamente em vez de lhe mostrar caracteres trocados: descodifica com validação estrita de UTF-8, por isso as sequências de bytes inválidas são reportadas como binário e não substituídas em silêncio por pontos de interrogação.

Última revisão . Encontrou algo desactualizado? Diga-nos.