Um token assinado que um servidor te entrega depois do login: isso é um JWT. Veja como ele funciona e os pontos-chave para usá-lo com segurança (sem passos de ataque).
Como funciona (três partes)
Um JWT é header.payload.signature unidos por .. O header e o payload são apenas codificados em base64url (não criptografados); só a assinatura é feita com uma chave secreta (ou compartilhada).
1. header
metadados como o algoritmo de assinatura. qualquer um pode ler
2. payload
claims como id do usuário e expiração. qualquer um pode ler = sem segredos
3. signature
feita com uma chave. garante a ausência de adulteração
O ponto-chave é que o conteúdo é "apenas legível". Então o payload não é lugar para senhas ou dados pessoais. O valor de um JWT é que, ao verificar a assinatura, o servidor pode confirmar "eu emiti este token e ele não foi alterado".
Defesas para usá-lo com segurança
Sempre verifique a assinatura e fixe o alg (o mais importante)
Verifique a assinatura no servidor toda vez. Fixe o algoritmo de assinatura (alg) aceito no valor que você espera e rejeite alg:none (sem assinatura). Não confie cegamente no alg escrito no header do token.
A RFC de boas práticas para JWT (RFC 8725) determina que as bibliotecas DEVEM permitir que quem as chama especifique o conjunto de algoritmos suportados e NÃO DEVEM usar nenhum outro, e que todas as operações criptográficas do JWT devem ser validadas, rejeitando o JWT inteiro se qualquer uma delas falhar.
Bloqueie a troca de algoritmo, não só o alg:none
O abuso do alg não se limita a remover a assinatura. A RFC 8725 descreve como trocar RS256 por HS256 faz algumas bibliotecas tentarem validar a assinatura com HMAC-SHA256 usando a chave pública RSA como segredo compartilhado (confusão de algoritmo). A chave pública é, por definição, pública — então, se isso funcionar, um atacante consegue criar ele mesmo uma assinatura válida.
A defesa é a mesma: não confie no alg do header; fixe o algoritmo que o servidor espera. Decida primeiro o algoritmo e depois verifique, em vez de escolher a rotina de verificação a partir do material de chave que você recebeu.
Valide para quem é e até quando vale
Uma assinatura válida só diz que o token é genuíno. Se ele é destinado a você e ainda está válido é uma verificação separada.
A RFC 7519 diz que, para aud, se quem processa a claim não se identificar com um valor de 'aud' quando ela estiver presente, o JWT DEVE ser rejeitado, e que exp identifica o momento a partir do qual o JWT NÃO DEVE ser aceito para processamento (nbf funciona da mesma forma na outra ponta). A RFC 8725 acrescenta que a aplicação deve validar que as chaves usadas pertencem ao emissor. Um token emitido legitimamente para outro serviço sendo aceito pelo seu é exatamente o resultado de pular essas checagens.
Não coloque segredos no payload
Suponha que qualquer pessoa pode decodificar o conteúdo. Mantenha segredos — senhas, dados pessoais, chaves de API — fora dele. Inclua apenas claims que não sejam catastróficos se vistos, como identificadores e permissões.
Mantenha a expiração curta e tenha como revogar
Faça os tokens de acesso de curta duração. Uma expiração longa demais estende a janela de dano se um for roubado. Se você precisa de revogação, combine um token de acesso de curta duração com um refresh/sessão gerenciado pelo servidor.
Use uma chave forte e armazene-a onde não possa ser roubada
Faça a chave de assinatura forte, não a reutilize e armazene-a em algum lugar seguro no servidor. Proteja também o próprio token — evite que seja roubado via XSS, carregue-o num cookie com atributos seguros (→ cuidado com o roubo via XSS).
A visão deste site: um JWT não é um mecanismo de sessão para todo uso
Os JWTs são muitas vezes usados para "manter o estado de login", mas têm uma fraqueza: a revogação é difícil. Se a assinatura é válida e não expirou, o servidor basicamente confia nela, então fazer um logout ou uma invalidação ter efeito imediato é complicado.
Nossa postura é: não use um JWT como substituto de longa duração para uma sessão. Combine um token de acesso de curta duração com um refresh/sessão revogável no servidor, e você obtém tanto a vantagem do JWT (verificação barata) quanto a revogação fácil.
Atenção: "decodificou" não é "é válido"
Como o conteúdo é legível, qualquer pessoa pode colar um JWT num decodificador de JWT e inspecionar o header e o payload. Mas decodificar (ler o conteúdo) e verificar (confirmar a autenticidade) são coisas inteiramente diferentes. Conseguir decodificar não garante nada sobre a validade.
O que decide se um token é genuíno é sempre a verificação da assinatura no servidor. Ler o conteúdo para depuração é prático — apenas não confunda "consegui ler" com "é válido".
JWT vs. sessões no servidor (cookies)
Um JWT é apenas uma das formas de manter o estado de login, e ele se encaixa melhor que uma sessão no servidor em alguns casos e pior em outros.
| Item | Sessão no servidor (cookie) | JWT |
|---|---|---|
| Onde fica o estado | No servidor (BD ou memória); o cookie guarda só um ID | Dentro do token; o servidor só verifica a assinatura |
| Logout / suspensão | Apagar no servidor tem efeito imediato | Aceito até expirar, a menos que você implemente revogação à parte |
| Visibilidade do conteúdo | Só um ID, nada para ler | Qualquer pessoa pode decodificar e ler |
| Melhor uso | Um aplicativo web comum em um único domínio | Vários serviços ou APIs verificando o mesmo token |
Para um aplicativo web que vive em um único domínio, uma sessão no servidor costuma bastar. Se você escolher JWT, emitir um token novo no login segue o mesmo princípio da defesa contra fixação de sessão.
Um caso real: uma biblioteca que não checava o algoritmo
A troca de algoritmo não é só teoria. A biblioteca de JWT para Node.js jsonwebtoken, muito usada, nas versões 4.2.1 e anteriores não checava corretamente o algoritmo indicado no header do token, o que permitia contornar a verificação (CVE-2015-9235, corrigida na 4.2.2). Um token que deveria ser verificado com chave pública podia ser assinado com um algoritmo de chave compartilhada (família HS) e ainda assim passar — exatamente a confusão de algoritmo descrita acima.
Duas lições:
- Mantenha a biblioteca atualizada. Você pode checar suas dependências contra vulnerabilidades conhecidas colando um lockfile no scanner de vulnerabilidades de dependências
- Não dependa dos padrões da biblioteca; declare explicitamente no seu código o algoritmo aceito
Como checar os seus próprios tokens
Cole um token emitido pelo seu próprio serviço no decodificador de JWT e observe os pontos abaixo. A decodificação roda no seu navegador e o token não é enviado a nenhum servidor. Mesmo assim, para um token de produção ativo, é sensato fazer logout depois para invalidá-lo.
- O
algdo header é o que você espera (e nãonone)? - Existe um
exp, e a validade a partir doiat(momento de emissão) é adequada ao uso? audeissestão presentes e apontam para o seu serviço?- O payload contém algo que você não gostaria que fosse visto — e-mails, telefones, chaves de API?
Cheque a verificação no servidor com testes em um ambiente de desenvolvimento. Um token com um caractere da assinatura alterado, um token com outro alg, um token expirado e um token destinado a outro serviço (aud errado) devem ser todos rejeitados — mantenha isso como teste automatizado.
Fontes (primárias)
- IETF RFC 8725, "JSON Web Token Best Current Practices" (em inglês) — datatracker.ietf.org (fixar algoritmos, validar todas as operações criptográficas, confusão de algoritmo, chaves pertencentes ao emissor)
- IETF RFC 7519, "JSON Web Token (JWT)" (em inglês) — datatracker.ietf.org (definições normativas de
exp,nbfeaud) - GitHub Advisory Database, "Verification Bypass in jsonwebtoken" (CVE-2015-9235) (em inglês) — github.com/advisories (afeta a 4.2.1 e anteriores; corrigida na 4.2.2)
- OWASP HTML5 Security Cheat Sheet (em inglês) — cheatsheetseries.owasp.org (não guardar identificadores de sessão no localStorage)
Leia a seguir
- Ferramenta: Decodificador / inspetor de JWT (verifique o conteúdo, detecte alg:none ou expiração)
- Design: falhas de design na redefinição de senha (em inglês; erros comuns do lado que emite tokens)
- Glossário: o que é XSS (uma rota clássica de roubo de token) / o que é CSRF / o que é fixação de sessão / o que é criptografia de chave pública
- Aprenda: escolhendo o MFA do jeito certo