Escalada de privilégios via JWT: um erro clássico de validação

Por: Cassio Shiga Casagrande

Imagem de um homem subindo escadas em direção a um servidor

29 de MAIO

Bom dia, boa tarde ou boa noite.

Me chamo Cassio Shiga Casagrande e atuo como Analista de Cibersegurança Red Team na Integrasul.

Este é meu primeiro post no blog e a proposta aqui é ir direto ao ponto: conteúdo técnico, prático e baseado em cenários reais de exploração. A ideia não é apenas explicar conceitos, mas demonstrar como falhas surgem na prática, como podem ser exploradas e, principalmente, onde está o erro de implementação.

Neste artigo, vamos analisar um caso clássico envolvendo JSON Web Tokens (JWT), onde uma validação incorreta permite manipulação do token e escalada de privilégios, um exemplo claro de como pequenas decisões de implementação podem comprometer toda a segurança de uma aplicação.

O que é?

JSON Web Tokens (JWT) são amplamente utilizados como mecanismo de autenticação em aplicações modernas, principalmente em APIs REST e arquiteturas stateless.

Em cenários vulneráveis, um simples ajuste no token pode permitir que qualquer usuário se torne administrador sem conhecer segredo nenhum e sem quebrar a codificação.

Um JWT é composto por três partes:
•    Header: define o algoritmo de assinatura 
•    Payload: contém as claims (dados do usuário) 
•    Signature: garante a integridade do token 

Formato:
header.payload.signature

O ponto crítico aqui é simples: a assinatura é o único mecanismo de confiança.
Sem validação correta dela, todo o restante perde valor.

Onde mora o problema?

Apesar do payload ser apenas codificado (Base64URL) e não criptografado, muitas implementações tratam seu conteúdo como confiável.

Na prática, o token é totalmente manipulável pelo cliente.

Se a validação da assinatura for falha, um atacante pode:
•    modificar os dados livremente 
•    forjar identidade 
•    escalar privilégios 
•    obter acesso total 

E isso nos leva a um dos erros mais clássicos: 

Aceitar o algoritmo: none

Vulnerabilidade: alg: none


A especificação original do JWT prevê suporte ao algoritmo none, que indica ausência de assinatura.
{
  "alg": "none",
  "typ": "JWT"
}

Em implementações seguras, isso deve ser explicitamente bloqueado.

O problema aparece quando a aplicação:
•    confia no alg vindo do cliente 
•    não força um algoritmo no backend 
•    ou utiliza bibliotecas/configurações inseguras 

Nesses cenários, o servidor pode:
- aceitar tokens sem assinatura
- confiar integralmente no payload

Exploração passo a passo

Para demonstrar o cenário na prática, subi um laboratório simples com uma API local responsável por gerar e validar tokens JWT.

1. Obter um JWT válido

Ao acessar o endpoint de login (http://localhost:3000/login), a aplicação retorna um token válido:
 


 
O “curl” é uma ferramenta de linha de comando usada para enviar requisições HTTP de forma simples, permitindo testar endpoints, manipular headers (como Authorization) e reproduzir chamadas de API sem precisar de interface gráfica.

Ao enviar esse token junto ao curl para o endpoint /admin, temos a resposta de “Acesso Negado”.


 



2. Decodificar

O JWT utiliza Base64URL, o que torna seu conteúdo trivial de decodificar.
Isso pode ser feito via terminal (com conversão para Base64 padrão) ou de forma mais prática utilizando JWT.io
 




Com a função Decoder da ferramenta jwt.io conseguimos ver os dados do token.

3. Modificar a “role” do payload de “user” para “admin”

{
  "user": "integrasul",
  "role": "admin"
}

4. Alterar o “alg” no header de “HS256” para “none”

{
  "alg": "none",
  "typ": "JWT"
}

5. Regerar o token

base64(header) + "." + base64(payload) + "."

- Sem assinatura

 

Alterando para a função Encoder da ferramenta jwt.io conseguimos alterar os dados do token.
 

6. Enviar para a aplicação
 


 

Resultado

Se a aplicação for vulnerável, o comportamento é direto:
• o token é aceito 
• o payload é confiado 
• o atacante obtém privilégios administrativos

- sem segredo
- sem brute force
- sem quebrar criptografia

Impacto


Essa falha leva diretamente a:
•    Account Takeover 
•    Privilege Escalation 
•    acesso à funções administrativas 
•    leitura/modificação de dados sensíveis 

Em APIs, isso geralmente implica comprometimento total da aplicação.

Causa raiz

O problema não está no JWT em si, mas na forma como ele é validado. O backend confia em dados controlados pelo cliente para definir como aplicar segurança. O algoritmo (alg) vem do próprio token. Se não houver validação rígida no servidor, o atacante passa a controlar o processo.

Boas práticas

• Não confiar no alg do token
  → definir explicitamente os algoritmos aceitos no backend 
• Validar sempre a assinatura 
• Validar claims críticas (iss, aud, exp) 
• Utilizar tokens de curta duração 
Armazenamento seguro no cliente
 → evitar localStorage
 → preferir cookies com HttpOnly, Secure, SameSite

Conclusão

JWT não é inseguro por definição. O risco surge quando a validação é mal implementada. Neste cenário, não foi necessário explorar nada complexo. Apenas manipular dados controlados pelo cliente. Quando a validação falha, o controle deixa de ser do servidor e passa a ser do atacante.

 

Assine a nossa newslettere receba as novidades da Integrasul em seu e-mail.

Enviando inscrição...

Obrigado pela sua inscrição!

Houve um erro no envio. Tente novamente mais tarde.

Você precisa aceitar a Política de Privacidade