JWT Aggiorna rotazione token: modello sicuro per sistemi reali
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:
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:
usedusato: truefamily_id)Passaggio 3: rilevamento replay
Se un token di aggiornamento contrassegnato come used: true viene presentato nuovamente, ciò significa che:
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
Proprietà Token di accesso Aggiorna token A vita 5–15 minuti 7–30 giorni __FormatoJWT (autonomo) Stringa opaca (consigliata) Archiviazione Memoria (variabile JS) httpSolo cookie Inviato a server API Solo server di autenticazione Rotazione Non necessario Ogni utilizzo 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