A Lacuna Entre Usar Algo e Entendê-lo
No início da minha carreira, estava depurando um problema de autenticação quando um desenvolvedor sênior perguntou: "O JWT está expirado?"
Eu disse que sim, que havia verificado. O que não admiti: tinha colado o token em um site, visto o timestamp de expiração, e ainda não entendia completamente o que estava olhando. Era seguro? Alguém poderia ler esse token? Estava criptografado? Por que qualquer site podia decodificá-lo se supostamente estava "assinado" e era "seguro"?
Este guia é para aquela versão de mim. Três conceitos que aparecem constantemente no desenvolvimento web, que a maioria dos tutoriais assume que você já conhece, e que na verdade são simples quando explicados com clareza.
Base64: Não É Criptografia. Não É Compressão. É Só Tradução.
A coisa mais importante que você precisa saber primeiro: Base64 não é um mecanismo de segurança. Não esconde seus dados. Qualquer um pode decodificá-lo instantaneamente. Se você já pensou "isso parece codificado então provavelmente é seguro colocar em uma URL" — não é.
Base64 é uma forma de representar dados binários usando apenas caracteres ASCII imprimíveis. É isso. A razão prática da sua existência: dados binários quebram coisas. Emails, cabeçalhos HTTP, URLs, atributos HTML — esses sistemas foram projetados para texto. Dados binários brutos, com seus bytes nulos e caracteres de controle, podem ser corrompidos ou alterados ao passar por sistemas baseados em texto.
Base64 converte binário para um alfabeto seguro de 64 caracteres: A–Z, a–z, 0–9, + e /. A saída é aproximadamente 33% maior que a entrada, mas garantidamente viaja intacta por qualquer sistema de texto.
Onde Você Vai Encontrar Isso de Verdade
Autenticação HTTP Basic: quando você se autentica com usuario:senha, as credenciais são codificadas em Base64 e enviadas no cabeçalho Authorization: Basic. Por isso Basic Auth sobre HTTP simples é perigoso — qualquer pessoa que intercepte a requisição pode decodificar as credenciais instantaneamente. HTTPS é obrigatório.
Tokens JWT: cada uma das três seções de um token JWT está codificada em Base64url (uma variante que substitui + e / por - e _ para ser segura em URLs).
Data URIs: <img src="data:image/png;base64,iVBORw0KGgo..."> — embutir dados de imagem diretamente em HTML ou CSS em vez de fazer uma requisição HTTP separada.
Anexos de email: a codificação MIME usa Base64 para que arquivos binários possam viajar por servidores de email projetados apenas para texto.
Teste você mesmo: cole qualquer texto no Codificador Base64 e veja o resultado. Depois cole a string codificada de volta para decodificá-la. Note que a versão "codificada" não esconde nada — apenas usa um alfabeto diferente.
JWT: Três Strings Base64 e uma Assinatura
Um JSON Web Token se parece com isso:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJleHAiOjE3MTM5MzYwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Exatamente dois pontos. Três seções.
Cabeçalho — a parte antes do primeiro ponto. Decodifica para metadados sobre o token: qual algoritmo de assinatura foi usado, que tipo de token é.
Payload — a seção do meio. Decodifica para os claims reais: ID do usuário, email, roles, tempo de expiração. Isso é o que seu backend lê para identificar o usuário.
Assinatura — a parte após o segundo ponto. Uma prova criptográfica de que o token não foi adulterado.
O Que Surpreende a Maioria dos Desenvolvedores
O payload está codificado em Base64url. Não está criptografado. Qualquer pessoa que tenha o token pode decodificar o payload e ler seu conteúdo — ID do usuário, email, roles, expiração, o que quer que você tenha colocado lá.
Cole qualquer JWT no Decodificador JWT e veja exatamente o que há dentro. Nenhuma chave é necessária.
Isso surpreende as pessoas porque a string parece um texto opaco embaralhado. Não é. O modelo de segurança do JWT é: "Posso verificar que este token foi genuinamente emitido pelo meu servidor (verificação de assinatura), então posso confiar nos claims que ele contém. Mas esses claims em si não são secretos."
A implicação prática: não coloque senhas, dados de pagamento ou informações pessoais sensíveis em payloads JWT. Coloque apenas o necessário para identificar e autorizar o usuário.
O Que a Assinatura Realmente Garante
A assinatura é criada pegando o cabeçalho + o payload + uma chave secreta que só o seu servidor conhece, e passando-os por uma função de hash. Quando seu servidor recebe um token, recalcula a assinatura usando o mesmo segredo. Se a assinatura recalculada corresponder à do token, o token é genuíno e não modificado.
Se alguém modificar o payload para mudar o ID do usuário de 123 para 456, a verificação de assinatura falha.
Por isso sua chave secreta de assinatura JWT precisa ser genuinamente secreta. Se um atacante obtê-la, pode falsificar tokens e se passar por qualquer usuário.
Hashing: Funções de Sentido Único
Uma função de hash pega qualquer entrada e produz uma saída de tamanho fixo. Duas propriedades a tornam útil para segurança:
Determinística: a mesma entrada sempre produz a mesma saída.
Sentido único: você não pode reverter o hash para obter a entrada original. Não existe dehash().
SHA-256("senha123") → ef92b778bafe771207...
SHA-256("senha124") → 88d4266fd4e6338d13...
Um caractere de diferença. Hash completamente diferente. Sem relação matemática entre entradas similares e saídas similares.
Por Que Senhas São Hasheadas, Não Criptografadas
Se as senhas fossem criptografadas, você poderia descriptografá-las com a chave correta. Se um atacante roubasse seu banco de dados e sua chave de criptografia, cada senha de usuário estaria exposta.
Com hashing: você armazena o hash, não a senha. Quando um usuário faz login, você hasheia o que ele digitou e compara com o hash armazenado. Você nunca precisa recuperar o original — só verificar uma tentativa.
Mesmo que um atacante obtenha seu banco de dados, ele tem apenas hashes. Para conseguir uma senha, ele precisa adivinhar e verificar, o que é muito mais lento.
MD5, SHA-256, bcrypt — Por Que Importa Qual Você Usa
MD5 era o padrão no início dos anos 2000. Agora está quebrado para propósitos de segurança. Uma GPU moderna pode calcular bilhões de hashes MD5 por segundo, o que significa que um atacante com seu banco de dados pode quebrar senhas simples em minutos. Nunca use MD5 para senhas.
SHA-256 é apropriado para verificação de integridade — confirmar que um arquivo não foi corrompido, gerar assinaturas HMAC para webhooks. Mas é rápido demais para senhas. Hashing rápido é ruim para senhas porque torna ataques de força bruta baratos.
bcrypt foi projetado especificamente para senhas. É intencionalmente lento — você pode ajustar quantas rodadas de cálculo ele realiza — e inclui um "salt" embutido (dados aleatórios) que garante que duas senhas idênticas produzam hashes completamente diferentes.
A regra: use bcrypt (ou Argon2, ou scrypt) para senhas. Use SHA-256 para todo o resto que precisar de verificação de integridade.
Referência Rápida
| Conceito | O Que É | Reversível? | Para Quê |
|---|---|---|---|
| Base64 | Codificação binário → texto | Sim, trivialmente | Transmitir dados binários por sistemas de texto |
| JWT | Token JSON assinado | Payload: sim. Assinatura: não | Autenticação sem estado |
| SHA-256 | Função de hash | Não | Integridade de arquivos, assinaturas HMAC |
| bcrypt | Hash de senha | Não | Armazenar senhas de usuários |
Entender essas três coisas corretamente evita uma classe de erros de segurança que parecem corretos na revisão de código e só são descobertos em produção — quando o dano já está feito.
As ferramentas: Base64, Decodificador JWT, Gerador de Hash. Use-as para testar sua compreensão, não apenas para obter resultados.