← Voltar ao Blog

JWT exp/iat/nbf Erros: Bugs de reivindicação de tempo que quebram Auth

Segurança do desenvolvedor27 de março de 2026·8 min de leitura
JWT time claims debugging
As declarações de tempo

JWT — exp, iat e nbf — são aparentemente simples. Eles são apenas carimbos de data/hora Unix. No entanto, eles causam alguns dos bugs de autenticação mais frustrantes na produção: tokens que expiram muito cedo, tokens que funcionam em um servidor, mas não em outro, e tokens que nunca expiram.

Este artigo aborda os bugs mais comuns de reivindicação de tempo, por que eles acontecem e como corrigi-los com padrões seguros.

Como funcionam exp, iat e nbf

Cada JWT pode transportar três declarações relacionadas ao tempo em sua carga útil:

Todos os três são datas numéricas: o número de segundos desde 1970-01-01T00:00:00Z (época Unix). Não milissegundos – segundos. Somente essa distinção causa cerca de 20% de todos os bugs de tempo do JWT.

Use nosso decodificador JWT para inspecionar declarações de tempo em qualquer token instantaneamente.

Bug nº 1: usando milissegundos em vez de segundos

JavaScript Date.now() retorna milissegundos. A especificação JWT requer segundos. Definir exp como Date.now() + 3600000 cria um token que expira no ano de 2089, não em uma hora.

// ERRADO — milissegundos
const exp = Date.now() + 3600000; // CORRETO — segundos
const exp = Math.floor(Data.now() / 1000) + 3600;

A maioria das bibliotecas JWT lidam com isso internamente, mas se você estiver criando cargas manualmente, esta é a primeira coisa a verificar.

Bug nº 2: reivindicação de exp totalmente ausente

Se você esquecer de definir exp, muitas bibliotecas criarão com prazer um token que nunca expira. Este é um risco de segurança: um token vazado permanece válido para sempre.

Sempre defina exp. Sempre valide-o no servidor. Se sua biblioteca não rejeita tokens sem exp por padrão, configure-a para fazer isso.

// Node.js jsonwebtoken - impor expiração
jwt.verify(token, segredo, { maxAge: '1h' });

Bug nº 3: distorção do relógio entre servidores

O servidor A emite um token às 14:00:00. O relógio do servidor B marca 13:59:55 (5 segundos atrasado). Se o token tiver nbf: 1711540800 (14:00:00), o Servidor B o rejeitará como "ainda não válido."

Isso é especialmente comum em:

A correção

Permite uma pequena tolerância de relógio (também chamada de "margem de manobra") — normalmente 30–60 segundos:

//jsonwebtoken
jwt.verify(token, segredo, { clockTolerance: 30 }); // José (Node.js)
aguarde jwtVerify(token, chave, { clockTolerance: '30s' });

Nunca defina a tolerância acima de 2 minutos. Se precisar de mais, corrija sua sincronização NTP.

Bug nº 4: pedido de validação errado

A ordem de validação correta é importante. Se você verificar a assinatura após verificar a expiração, um invasor poderá criar um token com um exp futuro que passe na verificação de tempo, mas tenha uma assinatura inválida.

Pedido de validação seguro:

  1. Decodificar cabeçalho (algoritmo de verificação)
  2. Verificar assinatura
  3. Verifique exp (rejeite se expirar)
  4. Verifique nbf (rejeite se ainda não for válido)
  5. Verifique iat (rejeite se for excessivamente antigo)
  6. Verifique o emissor, o público e outras reivindicações

A maioria das bibliotecas bem mantidas lidam com isso corretamente, mas o middleware personalizado geralmente erra.

Bug nº 5: confusão de fuso horário em iat

Os carimbos de data/hora JWT são sempre UTC. Mas às vezes os desenvolvedores os criam usando a hora local:

// ERRADO — fuso horário local
const iat = new Date('2026-03-27T14:00:00').getTime() / 1000; // CORRETO — UTC explícito
const iat = new Date('2026-03-27T14:00:00Z').getTime() / 1000;

Sem o sufixo Z, o JavaScript interpreta a string no fuso horário local, o que pode mudar o carimbo de data/hora em horas.

Bug #6: Aceitando tokens sem verificação nbf

A declaração nbf é útil para tokens de ativação atrasada — por exemplo, um token que só deve funcionar após uma implantação agendada. Se o seu validador ignorar nbf, esses tokens poderão ser usados antes do tempo de ativação pretendido.

A maioria das bibliotecas valida nbf por padrão, mas verifique isso em sua configuração, especialmente com middleware personalizado.

Bug nº 7: Expiração excessivamente longa

Definir exp para 30 dias para um token de acesso anula a finalidade dos tokens de curta duração. Melhores práticas:

Para padrões de token de atualização seguros, consulte nosso guia sobre Rotação de token de atualização JWT.

Casos de teste que toda API deveria ter

Adicione-os ao seu conjunto de testes para detectar bugs de reivindicação de tempo antecipadamente:

  1. Token com exp no passado → 401
  2. Token com exp exatamente agora → 401 (limite)
  3. Token sem exp → 401
  4. Token com nbf no futuro → 401
  5. Token com nbf ligeiramente no futuro (dentro da tolerância) → 200
  6. Token com iat no futuro → 401 (indica adulteração)
  7. Token com carimbos de data e hora em milissegundos → 401 (detecta o bug ms/s)

Padrões seguros para estruturas populares

Node.js (jsonwebtoken)

jwt.sign(carga útil, segredo, { expiresIn: '15m' });
jwt.verify(token, segredo, { clockTolerance: 30, maxAge: '15m'
});

Python (PyJWT)

jwt.decode(token, chave, algoritmos=['HS256'], margem de manobra = timedelta (segundos = 30), opções={'require': ['exp', 'iat']})

Vá (golang-jwt)

parser := jwt.NewParser( jwt.WithLeeway(30 * tempo.Segundo), jwt.WithValidMethods([]string{"HS256"}),
)

FAQ

Isso deveria ser obrigatório?

Embora a especificação JWT diga que iat é opcional, torná-lo obrigatório ajuda na depuração e nas trilhas de auditoria. Sem iat, você não pode determinar quando um token foi criado, dificultando a correlação com eventos de segurança.

Quanto desvio do relógio devo permitir?

Um padrão seguro comum é de 30 a 60 segundos. Mais de 2 minutos apresentam risco de segurança. Se seus sistemas precisarem de mais, corrija a sincronização NTP em vez de ampliar a margem de distorção.

Qual código de status HTTP devo retornar para um token expirado?

Return 401 Unauthorized com um corpo de erro claro como {"error": "token_expired"}. Não retorne 403 Forbidden — isso implica que o token é válido, mas não possui permissões, o que é uma situação diferente.

Ferramentas e artigos relacionados