Rotația jetoanelor de reîmprospătare JWT: model sigur pentru sisteme reale
[Securitatea dezvoltatorului28 martie 2026·9 minute de citire]] [
Majoritatea tutorialelor JWT se opresc la „utilizați un simbol de reîmprospătare pentru sesiuni de lungă durată”. Ei explică rareori ce se întâmplă când acel token de reîmprospătare este furat. Un simbol de reîmprospătare static – unul care nu se schimbă niciodată – oferă unui atacator același acces persistent ca un cookie de sesiune furat. Mai rău, nu există nicio modalitate de a detecta furtul.
Refresh token rotation solves this by issuing a new refresh token with every use. Dacă un jeton vechi este rejucat, întreaga sesiune este revocată. Acest articol prezintă modelul de implementare utilizat de Auth0, Okta și alți furnizori serioși de identitate.
De ce eșuează jetoanele de reîmprospătare statice
Un indicativ de reîmprospătare static are o valoare fixă pentru întreaga durată de viață a sesiunii (de multe ori peste 30 de zile). Probleme:
[Remedierea este de a trata fiecare jeton de reîmprospătare ca de unică folosință.
[ de rotațiePasul 1: Conectați-vă — Creați o familie de jetoane
Când utilizatorul se autentifică, generați un family_id (UUID) care grupează toate jetoanele din această sesiune:
{ 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
}
[ această înregistrare pe partea de server. Nu stocați niciodată jetoane de reîmprospătare în Stocare locală — utilizați Numai http cookie-uri sau stocare nativă securizată. Pasul 2: Reîmprospătarea simbolului — Rotiți
[ clientul prezintă indicativul de reîmprospătare: [ [ hash-ul simbolului în baza de dateutilizatutilizat: truefamily_id)Dacă un jeton de reîmprospătare marcat ca utilizat: true este prezentat din nou, aceasta înseamnă fie:
Răspunsul sigur: [ toate jetoanele din familie. Acest lucru obligă utilizatorul să se conecteze din nou. Este mai bine să deranjezi un utilizator legitim o dată decât să lași un atacator să mențină accesul.
// Reluare detectată — opțiune nucleară
așteaptă db.query( „ȘTERGERE FROM refresh_tokens WHERE family_id = $1”, [familyId]
);[ [ bazei de date
[ tabel minim de jetoane de reîmprospătare:
[CREATE TABLE refresh_tokens ( id UUID CHEIE PRIMARIA DEFAULT gen_random_uuid(), family_id UUID NOT NULL, user_id UUID NOT NULL REFERENCES utilizatori(id), token_hash TEXT NOT NULL UNIQUE, folosit BOOLEAN DEFAULT FALSE, creat_la TIMESTAMPTZ DEFAULT acum(), expires_at TIMESTAMPTZ NOT NULL, înlocuit_de REFERINȚE UUID refresh_tokens(id)
); CREATE INDEX idx_refresh_family ON refresh_tokens(family_id);
CREAȚI INDEX idx_refresh_user PE refresh_tokens(user_id);
Coloana înlocuită_de creează un lanț pe care îl puteți urmări în scopuri de audit.
În aplicațiile reale, mai multe apeluri API pot declanșa o reîmprospătare simultan. Dacă Apelul A rotește jetonul în timp ce Apelul B îl mai deține pe cel vechi, Apelul B declanșează detectarea reluării — deconectarea utilizatorului în mod neașteptat.
[ perioadei de grațiePermiteți indicativului de reîmprospătare anterior să rămână valabil pentru o fereastră scurtă (5-10 secunde) după rotație:
[const GRACE_PERIOD_MS = 10_000; if (token.used) { const elapsed = Date.now() - token.rotated_at; dacă (a trecut < 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');
} [ și alerte
[ aceste semnale în producție:
[
Jeton de reîmprospătare vs jeton de acces: Referință rapidă
[Pentru erorile de validare a revendicării de timp care interacționează adesea cu fluxurile de reîmprospătare, consultați Erorile comune JWT exp/iat/nbf.
[ [ frecventeCum ar trebui să gestionez solicitările de reîmprospătare simultane?
Utilizați o perioadă de grație scurtă (5–10 secunde) în care simbolul de reîmprospătare anterior este încă acceptat. Aceasta se ocupă de condițiile de cursă atunci când mai multe apeluri API declanșează o reîmprospătare simultan. După perioada de grație, doar cel mai nou simbol este valabil.
Tokenurile de reîmprospătare ar trebui să fie JWT sau șiruri opace?
Șirurile opace sunt în general mai sigure pentru jetoanele de reîmprospătare. JWT-urile transportă date de încărcare utilă care măresc suprafața de atac, iar jetoanele de reîmprospătare nu trebuie să fie autonome, deoarece oricum serverul le caută întotdeauna în baza de date.