Blog Series #2 — Seu JWT está protegido?
O JWT depende da assinatura para garantir que ninguém alterou o seu conteúdo. Se o segredo usado nessa assinatura for fraco ou exposto, um atacante pode criar tokens válidos e manipular a aplicação.


O JWT, ou JSON Web Token, é um dos formatos mais utilizados para autenticação em aplicações web e APIs. Depois que o usuário faz login, o servidor gera um token e o entrega ao cliente, que passa a enviá-lo em cada requisição, normalmente no cabeçalho Authorization. A partir desse token, o servidor identifica quem está fazendo a requisição e quais permissões essa pessoa possui.
Toda a segurança desse modelo depende de um único ponto: a assinatura. É ela que garante que o conteúdo do token foi gerado pelo servidor e não foi alterado no caminho. Quando o segredo usado para assinar o token é fraco ou acaba exposto, um atacante pode gerar seus próprios tokens e a aplicação passa a aceitá-los como se fossem legítimos.
O que é um JWT
Um JWT é formado por três partes separadas por ponto: o cabeçalho, o payload e a assinatura.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoiTWFyaWEiLCJyb2xlIjoidXNlciJ9.<assinatura>
O cabeçalho informa qual algoritmo foi utilizado para assinar o token:
{
"alg": "HS256",
"typ": "JWT"
}
O payload contém as informações que a aplicação utiliza para identificar o usuário, como o identificador, o nome e o perfil de acesso:
{
"sub": "123",
"name": "Maria",
"role": "user"
}
Um ponto importante é que essas duas primeiras partes não são criptografadas. Elas são apenas codificadas em Base64, o que significa que qualquer pessoa que tenha acesso ao token consegue ler o seu conteúdo. O JWT não foi feito para esconder informações, e sim para garantir que elas não sejam alteradas.
Como funciona a assinatura
A terceira parte do token é a assinatura. No algoritmo HS256, que é um dos mais comuns, o servidor pega o cabeçalho e o payload e calcula um HMAC utilizando um segredo que somente ele deveria conhecer.
Quando o token volta em uma requisição, o servidor refaz esse cálculo. Se o resultado for igual à assinatura presente no token, o servidor considera que o conteúdo é confiável. Se alguém alterar qualquer informação do payload, por exemplo trocando "role": "user" por "role": "admin", a assinatura deixa de corresponder e o token é rejeitado.
Isso significa que a proteção do JWT não está no token em si, mas no segredo utilizado para assiná-lo. Enquanto esse segredo permanecer desconhecido, ninguém consegue gerar uma assinatura válida para um payload modificado.
O risco de gerar assinaturas em sites
Durante o desenvolvimento, é comum utilizar sites que decodificam, validam e geram JWTs. Basta colar o token, informar o segredo e o site mostra o conteúdo e calcula a assinatura.
O problema aparece quando isso é feito com tokens e segredos reais. Ao colar o segredo de produção em um site de terceiros, ele deixa de estar apenas no servidor da aplicação. Não há como garantir o que acontece com essa informação depois de enviada: ela pode ser registrada, armazenada ou exposta de alguma forma que foge completamente do controle de quem a utilizou.
O mesmo vale para o token. Um token de produção representa a sessão de um usuário real e, enquanto estiver válido, pode ser utilizado por qualquer pessoa que tenha acesso a ele.
Gerar ou validar assinaturas deve ser responsabilidade da própria aplicação, com o segredo armazenado de forma segura no servidor. Para testes, o ideal é utilizar tokens e segredos criados especificamente para esse fim.
Quando o segredo pode ser quebrado
Mesmo que o segredo nunca seja colado em nenhum site, ainda existe outro risco. Um token assinado com HS256 contém tudo o que é necessário para testar se um determinado segredo está correto: o cabeçalho, o payload e a assinatura resultante.
Isso permite que um atacante que tenha obtido um token tente descobrir o segredo de forma offline, sem precisar fazer nenhuma requisição para a aplicação. Ferramentas como o Hashcat, amplamente utilizadas para quebra de senhas, conseguem testar uma enorme quantidade de possibilidades em pouco tempo, utilizando listas de palavras comuns e combinações.
Se o segredo for curto, previsível ou baseado em valores conhecidos, como o nome da aplicação, secret, 123456 ou um valor de exemplo copiado da documentação, ele pode ser descoberto rapidamente.
O impacto
Com o segredo em mãos, o atacante passa a ter a mesma capacidade que o servidor: ele consegue gerar tokens válidos com qualquer conteúdo.
Na prática, isso permite alterar o payload para se passar por outro usuário, trocando o valor de sub, ou elevar as próprias permissões, alterando o campo role para admin. Como a assinatura é calculada com o segredo correto, a aplicação não tem como diferenciar esse token de um token legítimo.
A partir desse ponto, tudo o que a aplicação controla com base no JWT fica comprometido: acesso a contas de outros usuários, painéis administrativos, endpoints internos da API e qualquer dado que dependa dessa autenticação.
Como se proteger
A principal medida é utilizar um segredo longo e gerado de forma aleatória, que não possa ser adivinhado nem encontrado em listas de palavras. Esse segredo deve ficar armazenado apenas no servidor, fora do código-fonte e do repositório.
Também é importante nunca utilizar segredos ou tokens de produção em sites de terceiros para decodificar ou gerar assinaturas.
Além disso, o servidor deve definir explicitamente qual algoritmo aceita, em vez de confiar no valor informado no cabeçalho do token, e os tokens devem ter um tempo de expiração curto. Em cenários em que vários serviços precisam validar tokens, algoritmos assimétricos, como o RS256, permitem que apenas o emissor tenha a chave privada usada para assinar, enquanto os demais serviços utilizam somente a chave pública para validar.
Integre DevSecOps ao seu fluxo de trabalho com o runtz agora
Comece a analisar riscos de segurança. Comece em runtz.dev.



