Base64, codificação de URL e JWT explicados
Esses três aparecem sempre que dados precisam viajar como texto: em URLs, cabeçalhos HTTP, JSON e tokens de login. Nenhum deles esconde nada. Este guia explica como cada um funciona, onde você vai encontrá-los e os erros por trás da maioria dos problemas.
Codificar não é criptografar
Codificar muda a forma como os dados são escritos para que atravessem um canal que só aceita certos caracteres. Qualquer pessoa pode desfazer isso, porque nenhuma chave está envolvida. A criptografia também altera os dados, mas só quem tem a chave consegue revertê-los. Um hash é outra coisa: uma impressão digital de mão única que não pode ser revertida, como explica Funções hash explicadas.
Base64 e codificação de URL são codificações. Um JWT costuma ser assinado, o que prova quem o emitiu e que não foi alterado, mas seu conteúdo é apenas codificado. Se um valor precisa permanecer secreto, ele precisa de criptografia, não de um desses formatos.
Como o Base64 funciona
O Base64 lê os dados de três em três bytes (24 bits) e os divide em quatro grupos de seis bits. Cada grupo é um número de 0 a 63, escrito como um caractere de um alfabeto de 64: A–Z para 0–25, a–z para 26–51, 0–9 para 52–61 e depois + e /. A palavra “Man” mostra os passos:
| Passo | M | a | n |
|---|---|---|---|
| Valores dos bytes | 77 | 97 | 110 |
| Bits | 01001101 | 01100001 | 01101110 |
| Quatro grupos de 6 bits | 010011 · 010110 · 000101 · 101110 = 19 · 22 · 5 · 46 | ||
| Base64 | T W F u → TWFu | ||
Quando o tamanho da entrada não é múltiplo de três, o último grupo é completado e marcado com preenchimento: um byte restante gera dois caracteres e ==, dois bytes restantes geram três caracteres e =. “Ma” vira TWE= e “M” vira TQ==.
Como cada três bytes viram quatro caracteres, o Base64 aumenta os dados em cerca de um terço, mais as quebras de linha que alguns formatos acrescentam. Uma foto de 3 MB enviada como anexo de e-mail viaja como cerca de 4 MB de texto, e uma imagem incorporada a uma folha de estilos como URL de dados fica cerca de um terço mais pesada que o arquivo.
Onde você encontra Base64
- Anexos de e-mail (MIME) são texto Base64, quebrado em linhas de 76 caracteres.
- URLs de dados como
data:image/png;base64,iVBORw0…colocam um arquivo pequeno direto no HTML ou no CSS. - A autenticação HTTP básica envia
user:passwordem Base64 no cabeçalho Authorization. Isso só esconde a senha de olhares casuais, por isso só é segura com HTTPS. - Certificados e chaves em arquivos PEM são Base64 entre as linhas
-----BEGIN …-----e-----END …-----, quebrado a cada 64 caracteres. - JSON e XML carregam valores binários, como uma assinatura ou uma miniatura, em strings Base64 porque não têm tipo binário.
Base64URL e preenchimento
O + e a / do Base64 padrão têm significado em URLs e caminhos de arquivo, então um segundo alfabeto, o Base64URL, usa - e _ no lugar. Ele também costuma omitir o preenchimento =, já que o decodificador consegue calcular o tamanho. JWTs, muitos tokens de API e alguns nomes de arquivo usam Base64URL. Para transformar Base64 padrão em Base64URL, troque + por -, / por _ e remova os = finais; para voltar, desfaça as trocas e acrescente = até o tamanho ser múltiplo de quatro.
Codificação por porcentagem em URLs
Uma URL só pode conter um conjunto limitado de caracteres, e alguns deles estruturam o endereço: / e ? separam o caminho e a consulta, & e = separam parâmetros, # inicia o fragmento. Quando um valor contém um desses caracteres, ou qualquer coisa fora do ASCII, ele é codificado por porcentagem: cada byte da sua forma UTF-8 é escrito como % seguido de dois dígitos hexadecimais. “café” vira caf%C3%A9, porque é corresponde aos dois bytes C3 A9.
Letras, dígitos e - . _ ~ nunca precisam ser codificados. Estes são os caracteres que mais causam problemas:
| Caractere | Codificado | Por que importa |
|---|---|---|
| espaço | %20 | Não é permitido em uma URL |
| & | %26 | Iniciaria um novo parâmetro |
| = | %3D | Encerraria o nome do parâmetro |
| ? | %3F | Iniciaria a consulta |
| # | %23 | Iniciaria o fragmento, que não é enviado ao servidor |
| / | %2F | Acrescentaria um segmento de caminho |
| + | %2B | É lido como espaço em dados de formulário |
| % | %25 | Iniciaria uma sequência de escape |
Codifique cada valor separadamente e depois monte a URL. Em JavaScript, encodeURIComponent faz isso para um valor e também codifica / ? & = #, enquanto encodeURI serve para um endereço inteiro e deixa esses caracteres como estão. Usar encodeURI em um único valor é uma causa comum de strings de consulta quebradas.
Sinais de mais, espaços e codificação dupla
Formulários HTML enviam seus campos como application/x-www-form-urlencoded, em que um espaço vira +. Na sintaxe geral de URLs, + é só um sinal de mais. Por isso, uma busca por “C++” enviada como q=C++ chega como “C” seguido de dois espaços a um servidor que decodifica dados de formulário; ela deveria ser enviada como q=C%2B%2B. Ao decodificar uma string de consulta à mão, descubra primeiro qual regra a gerou.
A codificação dupla acontece quando um valor já codificado é codificado de novo: %20 vira %2520, porque o próprio % vira %25. Se você vir %25 seguido de dois dígitos hexadecimais em uma URL, algo na cadeia codificou duas vezes; decodifique uma vez e procure onde está o passo a mais.
O que há dentro de um JWT
Um JSON Web Token (JWT) leva declarações (claims), como quem é o usuário e até quando o token vale, do sistema que o emite para os sistemas que o aceitam. A forma assinada comum tem três partes Base64URL separadas por pontos: um cabeçalho, uma carga útil e uma assinatura. Decodificadas, as duas primeiras são JSON comum:
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "user-42", "role": "editor", "iat": 1767225600, "exp": 1767229200}
O padrão (RFC 7519) define algumas declarações registradas; as aplicações acrescentam as suas, como role acima.
| Declaração | Significado |
|---|---|
| iss | Emissor: quem criou o token |
| sub | Sujeito: geralmente o ID do usuário ou da conta |
| aud | Público: o serviço ao qual o token se destina |
| exp, nbf, iat | Expira, não antes de, emitido em: tempo Unix em segundos |
| jti | ID do token, usado para detectar reutilização ou revogar um token específico |
Como a carga útil é apenas codificada, qualquer pessoa com o token pode lê-la. Não coloque dados pessoais nem segredos nela, e mantenha os tokens pequenos: eles viajam em cada requisição, e muitos servidores limitam o tamanho dos cabeçalhos.
Assinado não é secreto: como um JWT é verificado
A assinatura é calculada sobre o cabeçalho e a carga útil. Com HS256, emissor e receptor compartilham um segredo e usam HMAC com SHA-256. Com RS256 ou ES256, o emissor assina com uma chave privada e os receptores verificam com a chave pública correspondente, então eles não conseguem criar tokens por conta própria.
Um servidor que recebe um token precisa verificar a assinatura com o algoritmo e a chave esperados e conferir exp, nbf, iss e aud antes de confiar em qualquer declaração. Decodificar, como faz a ferramenta da LeedyBox, pula tudo isso: mostra o que o token diz, não se ele é autêntico. As bibliotecas também devem rejeitar o algoritmo “none”, que indica um token sem assinatura, a menos que tokens sem assinatura sejam esperados. Quando o próprio conteúdo precisa ficar oculto, o token é criptografado (JWE) e passa a ter cinco partes que não podem ser lidas sem a chave.
Problemas comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| O Base64 decodifica em texto embaralhado | Os dados são binários ou texto em outra codificação | Verifique o que foi codificado; salve dados binários como arquivo |
| “Caractere inválido” ao decodificar | Um prefixo data:, aspas ou o alfabeto Base64URL | Remova tudo antes da vírgula; use um decodificador que aceite - e _ |
| Um parâmetro chega cortado | Um & ou # não codificado no valor | Codifique cada valor com encodeURIComponent |
| %2520 em uma URL | O valor foi codificado duas vezes | Codifique uma vez, no ponto em que a URL é montada |
| Token rejeitado embora exp esteja no futuro | Público ou emissor errados, diferença de relógio ou chave diferente | Compare aud, iss e a chave de assinatura com o que o servidor espera |
| Data de expiração milhares de anos no futuro | exp escrito em milissegundos em vez de segundos | Guarde exp, nbf e iat em segundos |
Perguntas frequentes
O Base64 serve para proteger uma senha ou chave de API?
Não. Qualquer pessoa reverte Base64 em um segundo. Uma credencial codificada em Base64, por exemplo em um arquivo de configuração ou em uma URL, fica tão exposta quanto texto puro.
Posso colocar dados pessoais na carga útil de um JWT?
Evite. Qualquer um que tenha o token pode ler a carga útil, inclusive extensões do navegador, logs e proxies que veem a requisição. Coloque um ID no token e consulte os detalhes no servidor.
A codificação de URL protege contra ataques de injeção?
Só no sentido de que um valor não consegue quebrar a estrutura da URL. O servidor ainda precisa validar e escapar o valor decodificado de acordo com o lugar onde o usa, como SQL, HTML ou um comando de shell.
Por que minha string Base64 é maior que o arquivo?
Cada três bytes viram quatro caracteres, então o texto fica cerca de 33% maior, e as quebras de linha acrescentam um pouco mais. Para arquivos grandes, enviar os bytes diretamente é mais eficiente do que usar Base64.