Pular para o conteúdo
Categoria: Segurança da Informação9 min de leitura

Autenticação JWT: como funciona e onde ela falha

Por Lucas Andrade ·

Entenda como tokens JWT funcionam, por que dominam as APIs modernas e quais erros de implementação abrem brechas de segurança.

JSON Web Token, ou JWT, virou o padrão de fato para autenticação em APIs desde meados dos anos 2010. A promessa é simples: um token autocontido que carrega informações sobre o usuário e pode ser verificado sem precisar consultar um banco de dados a cada requisição. Na prática, essa mesma característica que torna o JWT rápido e escalável também é a raiz da maioria dos problemas de segurança que aparecem em auditorias. Entender o mecanismo por dentro é o primeiro passo para usá-lo sem abrir brechas.

O que é um JWT, na prática

Um JWT é uma string composta por três blocos separados por pontos: cabeçalho, payload e assinatura, cada um codificado em Base64Url. O cabeçalho descreve o algoritmo de assinatura usado. O payload carrega as chamadas claims — dados como identificador do usuário, papel, data de expiração e emissor. A assinatura garante que ninguém alterou o conteúdo depois que o servidor emitiu o token. É importante lembrar que Base64 não é criptografia: qualquer pessoa consegue decodificar o payload e ler seu conteúdo, então dados sensíveis nunca devem entrar ali.

As três partes de um token e o que cada uma protege

A assinatura é o que separa um token confiável de uma string qualquer. Ela pode ser gerada com um segredo simétrico, como HMAC-SHA256, ou com um par de chaves assimétricas, como RSA ou ECDSA. Serviços que emitem e validam o token no mesmo processo costumam usar HMAC. Já arquiteturas com múltiplos serviços validando tokens emitidos por um provedor central tendem a preferir chaves assimétricas, porque só quem tem a chave privada consegue assinar, enquanto qualquer serviço pode validar com a chave pública, sem risco de vazamento do segredo de assinatura.

Onde o JWT costuma falhar

O erro mais comum é aceitar o algoritmo declarado no próprio cabeçalho do token, incluindo o valor 'none', que dispensa assinatura — isso permite forjar tokens válidos sem conhecer nenhum segredo. Outro erro clássico é confundir chave pública com chave de verificação em esquemas assimétricos, permitindo que um atacante assine um token malicioso usando a chave pública como se fosse simétrica. Também é frequente ver tokens sem expiração curta, sem mecanismo de revogação e armazenados em localStorage, onde ficam expostos a qualquer script injetado via XSS.

Boas práticas para usar JWT com segurança

Sempre fixe o algoritmo esperado no lado da verificação, nunca confie no valor vindo do próprio token. Use tempos de expiração curtos, na casa de minutos para tokens de acesso, combinados com um refresh token de vida mais longa armazenado em cookie HttpOnly e Secure. Trate o payload como informação pública: nunca coloque senha, dado de cartão ou segredo interno ali. Para revogação real, mantenha uma lista de tokens invalidados ou prefira sessões opacas quando o caso de uso exigir logout imediato e confiável.

JWT é sempre a escolha certa?

Não necessariamente. Para aplicações com um único backend e necessidade de logout instantâneo, uma sessão tradicional guardada no servidor pode ser mais simples e mais segura. JWT brilha em cenários distribuídos, com múltiplos serviços que precisam validar identidade sem uma chamada de rede extra a cada requisição. A escolha certa depende da topologia do sistema, não de qual tecnologia está na moda.

Rotação de chaves e o campo kid

Vale também pensar em rotação de chaves e no que fazer quando um segredo de assinatura precisa ser trocado. Um esquema com identificador de chave no cabeçalho do token, o chamado kid, permite que o servidor mantenha múltiplas chaves válidas em paralelo durante a transição, verificando cada token com a chave correta sem invalidar sessões em andamento. Bibliotecas maduras de JWT já implementam essa checagem de forma correta, então evitar reinventar a validação na mão, com parsing manual do payload, reduz bastante a chance de introduzir uma das falhas clássicas descritas acima.

Escopo do token e menor privilégio

Vale ainda considerar o escopo do token: em vez de emitir um único JWT com acesso amplo a tudo, sistemas maduros costumam limitar cada token a um conjunto específico de permissões, ou claims de autorização, necessário para aquela sessão ou integração específica. Isso reduz o estrago possível caso um token vaze, já que o atacante herdaria apenas o subconjunto de acesso concedido, não as credenciais completas do usuário original — o mesmo princípio de menor privilégio aplicado a autenticação tradicional.

Refresh token: o parceiro do token de acesso

Um token de acesso com vida curta sozinho forçaria o usuário a fazer login novamente a cada poucos minutos, o que é inaceitável na maioria dos produtos. O refresh token resolve isso: um token de vida mais longa, armazenado com muito mais cuidado, usado exclusivamente para obter um novo token de acesso quando o anterior expira. Implementações maduras rotacionam o refresh token a cada uso e detectam reuso indevido — um sinal claro de que o token pode ter sido roubado — revogando toda a cadeia de sessão imediatamente ao detectar esse padrão.

Cookies versus header Authorization

Existem duas formas comuns de transportar um JWT em cada requisição: dentro de um cookie, enviado automaticamente pelo navegador, ou dentro do cabeçalho HTTP Authorization, incluído manualmente pelo código do cliente. Cookies com atributos HttpOnly e Secure protegem o token contra leitura por JavaScript malicioso, mas exigem proteção explícita contra CSRF, já que o navegador os envia automaticamente em qualquer requisição para o mesmo domínio. O cabeçalho Authorization não sofre com CSRF da mesma forma, porque exige código explícito para ser incluído, mas só funciona bem se o token nunca for armazenado em localStorage, onde fica vulnerável a XSS — a escolha entre os dois mecanismos envolve avaliar qual dessas duas classes de ataque é mais relevante para a arquitetura específica em questão.

Claims padronizadas versus claims customizadas

A especificação de JWT define um conjunto de claims registradas com significado padronizado, como exp para expiração, iat para o momento de emissão, iss para o emissor e aud para a audiência pretendida do token. Além dessas, qualquer aplicação pode adicionar claims customizadas com significado próprio, como papel do usuário ou identificador de organização em um sistema multi-tenant. Validar rigorosamente as claims padronizadas — em especial iss e aud — antes de aceitar um token evita que um token emitido para um propósito ou sistema diferente seja aceito indevidamente em outro contexto, um erro de validação incompleta que aparece com frequência em auditorias de segurança.

JWT em arquitetura de microsserviços

Em sistemas com múltiplos serviços independentes, o JWT resolve um problema real de desempenho: sem ele, cada serviço precisaria fazer uma chamada de rede ao serviço de autenticação toda vez que recebesse uma requisição, para confirmar que o usuário é quem diz ser. Com um token assinado e verificável localmente, cada serviço valida a assinatura com a chave pública do emissor e extrai as claims necessárias sem nenhuma chamada de rede adicional, reduzindo latência e removendo um ponto único de falha na cadeia de requisições. O custo dessa vantagem é justamente a dificuldade de revogar um token individual antes da sua expiração natural, já que nenhum serviço consulta um estado central a cada validação.

JWT em aplicações mobile

Aplicativos móveis apresentam um desafio adicional para o armazenamento seguro de tokens, já que não existe o conceito de cookie do navegador para se apoiar. Nesses casos, o armazenamento seguro recomendado usa o mecanismo nativo de keychain ou keystore do sistema operacional, protegido por criptografia própria do dispositivo, em vez de gravar o token em um arquivo de preferências simples que qualquer outro aplicativo com acesso root poderia ler. Além disso, aplicativos mobile costumam se beneficiar de tempos de expiração um pouco mais generosos para o token de acesso, compensados por biometria local exigida antes de qualquer operação sensível, já que reautenticar constantemente por senha prejudica bastante a experiência de uso em um dispositivo touch.

Auditoria e rastreabilidade de tokens

Sistemas maduros incluem, dentro das próprias claims do token, um identificador único de sessão, além do identificador do usuário, permitindo rastrear exatamente qual sessão específica realizou cada ação registrada em log. Isso se torna essencial durante uma investigação de incidente: sem esse identificador de sessão, fica muito mais difícil distinguir se duas requisições vieram do mesmo dispositivo logado ou de duas sessões diferentes do mesmo usuário, o que pode atrasar significativamente a resposta a um comprometimento de conta suspeito.

Perguntas frequentes sobre JWT

JWT é criptografado? Por padrão não — o formato mais comum, JWS, apenas assina o conteúdo, deixando-o legível por qualquer pessoa que o intercepte. Existe uma variante, JWE, que efetivamente criptografa o payload, mas é bem menos usada na prática. Posso simplesmente aumentar o tempo de expiração para evitar lidar com refresh token? Tecnicamente sim, mas isso amplia a janela de exposição de um token roubado, tornando o sistema mais vulnerável sem trazer benefício real de segurança.

Testando a implementação de JWT como parte do pentest

Validar a segurança de uma implementação de JWT durante um teste de invasão segue um roteiro específico: tentar trocar o algoritmo declarado no cabeçalho para 'none' e ver se o servidor aceita o token sem assinatura; tentar assinar um token forjado usando a chave pública como se fosse um segredo simétrico; verificar se o tempo de expiração é realmente respeitado no momento da validação; e confirmar se um token revogado continua sendo aceito indevidamente depois do logout. Cada um desses testes, quando bem-sucedido do ponto de vista do atacante, revela uma falha de implementação que precisa ser corrigida antes que o sistema vá para produção com dados reais de usuários.

No fim das contas, JWT é uma ferramenta poderosa quando usada com disciplina: algoritmo travado, expiração curta, payload sem segredo e armazenamento em cookie protegido. Os incidentes que aparecem em pentest quase sempre vêm da implementação, não do formato do token em si. Dominar esses detalhes é o que separa uma autenticação robusta de uma vulnerabilidade esperando para ser descoberta.

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly