← Torna al blog

JWT Aggiorna rotazione token: modello sicuro per sistemi reali

__Sicurezza sviluppatore28 marzo 2026·9 minuti di lettura

La maggior parte dei tutorial JWT si ferma a "usa un token di aggiornamento per sessioni di lunga durata". Raramente spiegano cosa succede quando il token di aggiornamento viene rubato. Un token di aggiornamento statico, che non cambia mai, fornisce a un utente malintenzionato lo stesso accesso persistente di un cookie di sessione rubato. Peggio ancora, non c'è modo di individuare il furto.

Rotazione del token di aggiornamento risolve questo problema emettendo un nuovo token di aggiornamento ad ogni utilizzo. Se viene riprodotto un vecchio token, l'intera sessione viene revocata. Questo articolo illustra il modello di implementazione utilizzato da Auth0, Okta e altri provider di identità seri.

Perché i token di aggiornamento statici non funzionano

Un token di aggiornamento statico ha un valore fisso per l'intera durata della sessione (spesso più di 30 giorni). Problemi:

  • Il furto è silenzioso — se un utente malintenzionato ruba il token di aggiornamento, può generare nuovi token di accesso a tempo indeterminato senza che l'utente lo sappia
  • Nessun rilevamento di replay: lo stesso token può essere utilizzato ripetutamente da posizioni diverse
  • La revoca è grossolana — per invalidare un token rubato, spesso è necessario invalidare tutte le sessioni utente
  • La soluzione consiste nel considerare ogni token di aggiornamento come monouso.

    Il modello di rotazione

    Passaggio 1: Accedi: crea una famiglia di token

    Quando l'utente si autentica, genera un family_id (UUID) che raggruppa tutti i token in questa sessione:

    { family_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479", user_id: "user_123", refresh_token_hash: sha256(refresh_token), created_at: "2026-03-28T10:00:00Z", expires_at: "2026-04-27T10:00:00Z", used: false
    }

    Memorizza questo record sul lato server. Non archiviare mai i token di aggiornamento in localStorage: utilizza i cookie httpOnly o l'archiviazione nativa sicura.

    Passaggio 2: aggiornamento token: ruota

    Quando il client presenta il token di aggiornamento:

  • Cerca l'hash del token nel database
  • Verifica che appartenga a una famiglia attiva e che non sia contrassegnato come used
  • Contrassegnalo come usato: true
  • Emetti un new token di aggiornamento (nuovo valore casuale, stesso family_id)
  • Emetti un nuovo token di accesso
  • Memorizza il nuovo hash del token di aggiornamento
  • Passaggio 3: rilevamento replay

    Se un token di aggiornamento contrassegnato come used: true viene presentato nuovamente, ciò significa che:

  • Un utente malintenzionato sta riproducendo un token rubato oppure
  • Un client legittimo sta riprovando dopo un errore di rete
  • La risposta sicura: revoca tutti i token nella famiglia. Ciò costringe l'utente ad accedere nuovamente. È meglio disturbare un utente legittimo una volta piuttosto che consentire a un utente malintenzionato di mantenere l'accesso.

    // Replay rilevato: opzione nucleare
    attendi db.query( 'ELIMINA DA refresh_tokens DOVE family_id = $1', [IDfamiglia]
    ); 

    Schema database

    Una tabella di token di aggiornamento minimo:

    CREA TABELLA aggiorna_tokens ( id UUID CHIAVE PRIMARIA PREDEFINITA gen_random_uuid(), family_id UUID NON NULL, user_id UUID NON RIFERIMENTI NULL users(id), token_hash TESTO NON NULL UNICO, utilizzato BOOLEAN DEFAULT FALSE, creato_al TIMESTAMPTZ DEFAULT ora(), scade_at TIMESTAMPTZ NON NULL, sostituito_da RIFERIMENTI UUID refresh_tokens(id)
    ); CREA INDICE idx_refresh_family ON refresh_tokens(family_id);
    CREA INDICE idx_refresh_user ON refresh_tokens(user_id);

    La colonna replaced_by crea una catena che puoi seguire a scopo di controllo.

    Gestione di richieste simultanee

    Nelle applicazioni reali, più chiamate API potrebbero attivare un aggiornamento contemporaneamente. Se la chiamata A ruota il token mentre la chiamata B mantiene ancora quello vecchio, la chiamata B attiva il rilevamento della riproduzione, disconnettendo l'utente inaspettatamente.

    Schema periodo di grazia

    Consenti al token di aggiornamento precedente di rimanere valido per un breve periodo (5–10 secondi) dopo la rotazione:

    const GRACE_PERIOD_MS = 10_000; if (token.usato) { const trascorso = Date.now() - token.rotated_at; se (trascorso < GRACE_PERIOD_MS) { // Within grace period — return the already-issued new tokens return getLatestTokensForFamily(token.family_id); } // Outside grace period — replay attack await revokeFamily(token.family_id); throw new UnauthorizedError('token_replayed');
    }

    Monitoraggio e avvisi

    Traccia questi segnali in produzione:

  • Eventi di riproduzione all'ora: un picco indica un attacco attivo o un bug lato client
  • Revoche familiari: tassi elevati possono indicare il furto di token o un client non configurato correttamente
  • __Frequenza di aggiornamento per utente: frequenze anormalmente elevate suggeriscono la raccolta di token
  • __Anomalie geografiche: aggiorna da un paese diverso rispetto al login originale
  • Token di aggiornamento e token di accesso: riferimento rapido

    __Formato

    Per i bug di convalida delle richieste temporali che spesso interagiscono con i flussi di aggiornamento, vedere JWT exp/iat/nbf bug comuni.

    FAQ

    Come devo gestire le richieste di aggiornamento simultanee?

    Utilizza un breve periodo di grazia (5-10 secondi) in cui il token di aggiornamento precedente è ancora accettato. Gestisce le condizioni di competizione quando più chiamate API attivano un aggiornamento contemporaneamente. Dopo il periodo di tolleranza, solo il token più recente è valido.

    I token di aggiornamento dovrebbero essere JWT o stringhe opache?

    Le stringhe opache sono generalmente più sicure per i token di aggiornamento. I JWT trasportano dati di carico che aumentano la superficie di attacco e non è necessario che i token di aggiornamento siano autonomi poiché il server li cerca comunque sempre nel database.

    Per quanto tempo dovrebbero durare le sessioni di aggiornamento?

    7–30 giorni è il valore tipico. Le applicazioni ad alta sicurezza (banche, sanità) dovrebbero impiegare 1-7 giorni. Le app consumer possono durare fino a 90 giorni con rotazione. Associa sempre sessioni lunghe al rilevamento delle impronte digitali del dispositivo e al rilevamento delle anomalie.

    Strumenti e articoli correlati

  • Decodificatore JWT: ispeziona i token e verifica le dichiarazioni di tempo
  • Errori di sicurezza JWT: insidie ​​comuni di JWT oltre i token di aggiornamento
  • __JWT Bug di rivendicazione temporale: disallineamento dell'orologio e problemi con l'ordine di convalida
  • __Guida 2FA: rafforza l'autenticazione oltre i token
  • ProprietàToken di accessoAggiorna token
    A vita5–15 minuti7–30 giorni
    JWT (autonomo)Stringa opaca (consigliata)
    ArchiviazioneMemoria (variabile JS)httpSolo cookie
    Inviato aserver APISolo server di autenticazione
    RotazioneNon necessarioOgni utilizzo