← Torna al blog

JWT exp/iat/nbf Errori: bug di time-claim che interrompono l'autenticazione

__Sicurezza sviluppatore27 marzo 2026·8 minuti di lettura
Le dichiarazioni temporali di

JWT - exp, iat e nbf - sono ingannevolmente semplici. Sono solo timestamp Unix. Eppure causano alcuni dei bug di autenticazione più frustranti nella produzione: token che scadono troppo presto, token che funzionano su un server ma non su un altro e token che non scadono mai.

Questo articolo tratta i bug più comuni legati ai time-claim, il motivo per cui si verificano e come risolverli con impostazioni predefinite sicure.

Come funzionano exp, iat e nbf

Ogni JWT può trasportare tre richieste legate al tempo nel suo carico utile:

  • exp (Tempo di scadenza) — il token NON DEVE essere accettato dopo questo timestamp
  • iat (Rilasciato a) — quando il token è stato creato
  • nbf (Non prima) — il token NON DEVE essere accettato prima di questo timestamp
  • Tutti e tre sono date numeriche: il numero di secondi dal 1970-01-01T00:00:00Z (epoca Unix). Non millisecondi, secondi. Questa distinzione da sola causa circa il 20% di tutti i bug temporali JWT.

    Utilizza il nostro Decodificatore JWT per controllare istantaneamente le dichiarazioni di tempo in qualsiasi token.

    Bug n. 1: utilizzo dei millisecondi anziché dei secondi

    JavaScript Date.now() restituisce millisecondi. Le specifiche JWT richiedono pochi secondi. Impostando exp su Date.now() + 3600000 crea un token che scade nell'anno 2089, non tra un'ora.

    // SBAGLIATO — millisecondi
    const exp = Date.now() + 3600000; // CORRETTO: secondi
    const exp = Math.floor(Date.now() / 1000) + 3600;

    La maggior parte delle librerie JWT lo gestiscono internamente, ma se stai creando i payload manualmente, questa è la prima cosa da controllare.

    Bug n. 2: richiesta di esperienza mancante completamente

    Se dimentichi di impostare exp, molte biblioteche creeranno volentieri un token che non scade mai. Questo è un rischio per la sicurezza: un token trapelato rimane valido per sempre.

    Imposta sempre exp. Convalidalo sempre sul server. Se la tua libreria non rifiuta i token senza exp per impostazione predefinita, configurala per farlo.

    // Node.js jsonwebtoken: applica la scadenza
    jwt.verify(token, segreto, { maxAge: '1h' });

    Bug n. 3: disallineamento dell'orologio tra i server

    Il server A emette un token alle 14:00:00. L'orologio del server B segna 13:59:55 (5 secondi indietro). Se il token ha nbf: 1711540800 (14:00:00), il server B lo rifiuta come "non ancora valido".

    Ciò è particolarmente comune in:

  • Architetture di microservizi con orologi non sincronizzati
  • Funzioni serverless in cui i contenitori hanno una deriva dell'orologio
  • App mobili in cui l'orologio del dispositivo è impostato manualmente
  • La soluzione

    Consenti una piccola tolleranza orologio (chiamata anche "margine di manovra") - in genere 30-60 secondi:

    // jsonwebtoken
    jwt.verify(token, segreto, { clockTolerance: 30 }); // jose (Node.js)
    attendono jwtVerify(token, chiave, { clockTolerance: '30s' });

    Non impostare mai una tolleranza superiore a 2 minuti. Se ne hai bisogno di più, correggi invece la sincronizzazione NTP.

    Bug n. 4: ordine di convalida errato

    L'ordine di convalida corretto è importante. Se controlli la firma dopo aver controllato la scadenza, un utente malintenzionato può creare un token con un futuro exp che supera il controllo temporale ma ha una firma non valida.

    Ordine di convalida sicuro:

  • Decodifica intestazione (controllo algoritmo)
  • Verifica firma
  • Controlla exp (rifiuta se scaduto)
  • Controlla nbf (rifiuta se non ancora valido)
  • Controlla iat (rifiuta se irragionevolmente vecchio)
  • Verifica emittente, pubblico e altre affermazioni
  • La maggior parte delle librerie ben gestite gestisce correttamente questo problema, ma il middleware personalizzato spesso sbaglia.

    Bug n. 5: confusione sul fuso orario in iat

    I timestamp di

    JWT sono sempre UTC. Ma gli sviluppatori a volte li creano utilizzando l'ora locale:

    // SBAGLIATO: fuso orario locale
    const iat = new Date('2026-03-27T14:00:00').getTime() / 1000; // CORRETTO: UTC esplicito
    const iat = new Date('2026-03-27T14:00:00Z').getTime() / 1000;

    Senza il suffisso Z, JavaScript interpreta la stringa nel fuso orario locale, che può spostare il timestamp di ore.

    Bug n. 6: accettazione di token senza controllo nbf

    L'attestazione nbf è utile per i token ad attivazione ritardata, ad esempio un token che dovrebbe funzionare solo dopo una distribuzione pianificata. Se il tuo validatore ignora nbf, questi token possono essere utilizzati prima del tempo di attivazione previsto.

    La maggior parte delle librerie convalida nbf per impostazione predefinita, ma verificalo nella configurazione, in particolare con il middleware personalizzato.

    Bug n. 7: scadenza eccessivamente lunga

    Impostare exp su 30 giorni per un token di accesso vanifica lo scopo dei token di breve durata. Migliori pratiche:

  • Token di accesso: 5-15 minuti
  • Aggiorna token: 7–30 giorni (con rotazione)
  • ID: 1 ora
  • Per modelli di token di aggiornamento sicuri, consulta la nostra guida su JWT rotazione dei token di aggiornamento.

    Casi di test che ogni API dovrebbe avere

    Aggiungili alla tua suite di test per individuare tempestivamente i bug relativi alle richieste di tempo:

  • Token con exp nel passato → 401
  • Token con exp esattamente adesso → 401 (confine)
  • Token senza exp → 401
  • Token con nbf in futuro → 401
  • Token con nbf leggermente nel futuro (entro la tolleranza) → 200
  • Token con iat nel futuro → 401 (indica manomissione)
  • Token con timestamp in millisecondi → 401 (rileva il bug ms/s)
  • Impostazioni predefinite sicure per i framework più diffusi

    Node.js (jsonwebtoken)

    jwt.sign(carico utile, segreto, { expiresIn: '15m' });
    jwt.verify(token, segreto, { clockTolerance: 30, maxAge: '15m'
    });

    Pitone (PyJWT)

    jwt.decode(token, chiave, algoritmi=['HS256'], scarto=timedelta(secondi=30), opzioni={'require': ['exp', 'iat']})

    Vai (golang-jwt)

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

    FAQ

    Dovrebbe essere obbligatorio?

    Mentre le specifiche JWT dicono che iat è facoltativo, renderlo obbligatorio aiuta con il debug e gli audit trail. Senza iat, non è possibile determinare quando è stato creato un token, rendendo più difficile la correlazione con gli eventi di sicurezza.

    Quanto spostamento dell'orologio devo consentire?

    Un valore predefinito comune e sicuro è 30-60 secondi. Più di 2 minuti comportano rischi per la sicurezza. Se i tuoi sistemi necessitano di più, correggi la sincronizzazione NTP invece di ampliare il limite di distorsione.

    Quale codice di stato HTTP devo restituire per un token scaduto?

    Restituisci 401 Non autorizzato con un corpo dell'errore chiaro come {"error": "token_expired"}. Non restituire 403 Forbidden: ciò implica che il token è valido ma non dispone di autorizzazioni, il che è una situazione diversa.

    Strumenti e articoli correlati

  • Decodificatore JWT: controlla le dichiarazioni di tempo in qualsiasi token
  • Errori di sicurezza JWT: insidie ​​JWT più ampie oltre le affermazioni temporali
  • Aggiorna rotazione token: modello sicuro per sessioni di lunga durata
  • Guida 2FA: aggiungi un secondo livello oltre i token