Guias JWT

JWT alg none: Riscos e Tratamento Seguro

Entenda o que alg none significa, por que um JWT sem assinatura não tem integridade criptográfica e como usar allowlist de algoritmos em vez de confiar no header.

Por JWTDecoder.toolsÚltima verificação em 2026-09-12

Voz editorial: a primeira pessoa descreve o fluxo de trabalho documentado do JWTDecoder.tools; JWTDecoder.tools é o editor e autor organizacional.

alg=none ∉ application allowlist
token alg → application allowlist → accept / reject

Quando decodifico um JWT e vejo:

{
  "alg": "none"
}

paro de tratá-lo como um token assinado normal. alg: none representa um JWS não protegido por assinatura ou MAC. O cabeçalho e o payload podem continuar legíveis, mas não existe integridade criptográfica no próprio JWS.

Minha primeira pergunta é:

A aplicação definiu explicitamente este contexto como um caso em que JWT sem assinatura é permitido?

Se a resposta é não, rejeito.

O que alg: none significa

A RFC 7518 define none como o algoritmo Unsecured JWS. A RFC 7519 também mostra um exemplo de Unsecured JWT.

No formato compacto, ainda existem três segmentos:

header.payload.

O segmento de assinatura está vazio.

Consigo ler cabeçalho e payload no Decodificador JWT, mas marco o resultado como dados decodificados, não como claims autenticados.

Por que o header não pode definir minha política

Um padrão perigoso seria:

if (header.alg === "none") {
  acceptWithoutSignature();
}

Não projeto verificadores assim.

Antes da autenticação, o JWT inteiro é entrada não confiável. Se deixo header.alg decidir se assinatura é necessária, dou ao token controle sobre a política que deveria protegê-lo.

Prefiro configuração explícita:

const allowedAlgorithms = ["RS256"];

E exijo que o algoritmo recebido esteja dentro desse conjunto.

A RFC 8725 recomenda que bibliotecas permitam ao chamador definir algoritmos aceitos e não processem outros algoritmos automaticamente.

A falha histórica que quero evitar

O problema clássico com alg: none não era a existência do formato em si. Era a combinação de implementações permissivas com a ideia de que o algoritmo informado pelo token poderia determinar como autenticar o próprio token.

Um token assinado podia ser modificado conceitualmente para:

  1. trocar alg para none;
  2. alterar claims;
  3. remover a assinatura;
  4. depender de um verifier quebrado que aceitasse o modo sem assinatura.

O controle correto está na allowlist da aplicação, não em “detectar payload suspeito” depois.

Decodificar continua sendo possível

Um JWT sem assinatura pode carregar:

{
  "sub": "user_123",
  "role": "admin",
  "exp": 1789203600
}

Esses valores mostram o que o token afirma. Sem assinatura/MAC, qualquer pessoa capaz de construir o token pode escolher esses claims.

Por isso, nunca uso:

payload parseou
→ role parece válida
→ usuário autenticado

Se o fluxo exige autenticação, aplico as proteções criptográficas definidas pela aplicação.

none não é universalmente proibido pelo formato

A RFC 7518 reconhece Unsecured JWS. A RFC 8725 observa que none pode existir em contextos explicitamente protegidos por outro mecanismo, mas geração/consumo desse modo deve ser intencional.

Essa palavra — explicitamente — é a parte que considero essencial.

Não crio uma opção global como:

allowUnsignedJwt = true

para uma aplicação que recebe vários tipos de JWT.

Se há um perfil legítimo que usa JWT sem assinatura porque a integridade está garantida em outra camada, isolo esse perfil com regras próprias e mutuamente exclusivas das regras de autenticação de JWT assinado.

Como configuro um verifier na prática

A API exata depende da biblioteca, mas a política que procuro é semelhante a:

verifyJwt(token, trustedKey, {
  algorithms: ["RS256"],
  issuer: "https://login.example.com/",
  audience: "api://orders"
});

O algoritmo permitido vem da configuração confiável. Se chega alg: none, a biblioteca deve rejeitar salvo se aquele modo foi habilitado explicitamente para o contexto correto.

alg none não é o mesmo que assinatura inválida

São estados diferentes.

Assinatura inválida: existe uma assinatura, mas ela não verifica com a chave esperada.

alg: none: o token declara que não usa algoritmo de assinatura e o segmento de assinatura fica vazio.

Se um fluxo que normalmente produz RS256 passa a gerar none, investigo a origem do token e a configuração do issuer imediatamente. Tentar outra chave pública não resolve um token que não possui assinatura.

Também valido o restante da política

Mesmo usando um algoritmo permitido, ainda verifico:

  • assinatura;
  • issuer confiável;
  • audience;
  • exp e nbf;
  • tipo/profile do token;
  • scopes e roles exigidos.

O Validador JWT mostra essa separação. O Verificador de Assinatura JWT trabalha apenas com algoritmos suportados explicitamente em vez de executar qualquer alg arbitrário.

Se alg: none aparecer inesperadamente em produção

Meu checklist é:

  1. Decodifico e confirmo "alg":"none".
  2. Confirmo que o segmento de assinatura está vazio.
  3. Identifico qual serviço criou o token.
  4. Verifico qual algoritmo a aplicação espera em configuração confiável.
  5. Confiro se a biblioteca tem allowlist explícita.
  6. Rejeito none se não estiver permitido para aquele perfil.
  7. Procuro fallbacks que pulem verificação.
  8. Reviso logs por mudanças inesperadas de algoritmo.

Não “conserto” o token trocando none para RS256. Mudar o header não cria uma assinatura válida.

Minha regra é direta: a aplicação decide se um JWT sem assinatura é permitido; o próprio token nunca recebe autoridade para tomar essa decisão.

Fontes e referências

Guias relacionados