JWT Odśwież rotacja tokena: bezpieczny wzorzec dla systemów rzeczywistych

Większość samouczków JWT kończy się na „użyciu tokena odświeżania w przypadku długotrwałych sesji”. Rzadko wyjaśniają, co się stanie, gdy ten token odświeżania zostanie skradziony. Statyczny token odświeżania — taki, który nigdy się nie zmienia — zapewnia atakującemu taki sam stały dostęp, jak skradziony plik cookie sesji. Co gorsza, nie ma możliwości wykrycia kradzieży.
Rotacja tokena odświeżania rozwiązuje ten problem, wydając nowy token odświeżania przy każdym użyciu. Jeśli stary token zostanie odtworzony ponownie, cała sesja zostanie unieważniona. W tym artykule omówiono wzorzec implementacji używany przez Auth0, Okta i innych poważnych dostawców tożsamości.
Dlaczego tokeny odświeżania statycznego nie działają
Statyczny token odświeżania ma stałą wartość przez cały czas życia sesji (często ponad 30 dni). Problemy:
- Kradzież jest cicha — jeśli atakujący ukradnie token odświeżania, może generować nowe tokeny dostępu w nieskończoność bez wiedzy użytkownika
- Brak wykrywania powtórek — ten sam token może być używany wielokrotnie z różnych lokalizacji
- Odwołanie jest brutalne — aby unieważnić jeden skradziony token, często trzeba unieważnić wszystkie sesje użytkownika
Poprawka polega na traktowaniu każdego tokena odświeżania jako jednorazowego użytku.
Model rotacyjny
Krok 1: Zaloguj się — Utwórz rodzinę tokenów
Gdy użytkownik się uwierzytelnia, wygeneruj family_id (UUID), który grupuje wszystkie tokeny w tej sesji:
{ 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
}Przechowuj te rekordy po stronie serwera rekordów. Nigdy nie przechowuj tokenów odświeżania w localStorage — używaj plików cookie httpOnly lub bezpiecznego magazynu natywnego.
Krok 2: Odświeżenie tokena — Obróć
Kiedy klient przedstawia token odświeżania:
- Sprawdź skrót tokena w bazie danych
- Sprawdź, czy należy do aktywnej rodziny i nie jest oznaczony jako
used - Oznacz jako
used: true - Wydaj nowy token odświeżenia (nowa losowa wartość, ta sama
family_id) - Wydaj nowy token dostępu
- Przechowuj nowy skrót tokena odświeżania
Krok 3: Wykrywanie powtórki
Jeśli token odświeżania oznaczony jako użyty: true zostanie zaprezentowany ponownie, oznacza to albo:
- Atakujący odtwarza skradziony token lub
- Prawny klient podejmuje ponowną próbę po awarii sieci
Bezpieczna reakcja: unieważnij wszystkie tokeny w rodzinie. Zmusza to użytkownika do ponownego zalogowania się. Lepiej raz sprawić kłopot legalnemu użytkownikowi, niż pozwolić atakującemu zachować dostęp.
// Wykryto powtórkę – opcja nuklearna
czekaj db.query( 'USUŃ Z tokenów odświeżania GDZIE id_rodziny = 1 $', [identyfikator rodziny]
);Schemat bazy danych
Tabela tokenów minimalnego odświeżania:
UTWÓRZ TABELĘ odśwież_tokens ( id UUID KLUCZ PODSTAWOWY DOMYŚLNY gen_random_uuid(), Family_id UUID NIE NULL, user_id UUID NIE NULL ODNIESIENIA użytkownicy (id), token_hash TEKST NIE NULL UNIKALNY, używane BOOLEAN DOMYŚLNE FAŁSZ, utworzony_at TIMESTAMPTZ DOMYŚLNY teraz(), wygasa_o TIMESTAMPTZ NIE NULL, zastąpione_by ODNOŚNIKI UUID odśwież_tokens(id)
); UTWÓRZ INDEKS idx_refresh_family NA odśwież_tokens(family_id);
UTWÓRZ INDEKS idx_refresh_user NA odśwież_tokens(id_użytkownika);Kolumna replaced_by tworzy łańcuch, który możesz śledzić do celów audytu.
Obsługa współbieżnych żądań
W rzeczywistych aplikacjach wiele wywołań API może jednocześnie wywołać odświeżenie. Jeśli połączenie A zmieni token, podczas gdy połączenie B nadal zachowa stary, połączenie B uruchomi wykrywanie powtórki — nieoczekiwane wylogowanie użytkownika.
Wzorzec okresu karencji
Pozwól, aby poprzedni token odświeżania pozostał ważny przez krótkie okno (5–10 sekund) po rotacji:
const GRACE_PERIOD_MS = 10_000; if (token.used) { const, który upłynął = Date.now() - token.rotated_at; jeśli (upłynęło < 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');
}Monitorowanie i alerty
Śledź te sygnały w produkcji:
- Powtórz zdarzenia na godzinę — skok oznacza aktywny atak lub błąd po stronie klienta
- Odwołania rodzinne — wysokie wskaźniki mogą wskazywać na kradzież tokena lub błędną konfigurację klienta
- Częstotliwość odświeżania na użytkownika — nienormalnie wysokie współczynniki sugerują zbieranie tokenów
- Anomalie geograficzne — odśwież z innego kraju niż oryginalny login
Token odświeżenia a token dostępu: skrócona instrukcja
| Właściwość | Token dostępu | Odśwież token |
|---|---|---|
| Czas życia | 5–15 minut | 7–30 dni |
| Format | JWT (samodzielny) | Nieprzezroczysty ciąg (zalecany) |
| Przechowywanie | Pamięć (zmienna JS) | httpTylko plik cookie |
| Wysłano do | serwery API | Tylko serwer autoryzacji |
| Obrót | Nie potrzebne | Przy każdym użyciu |
Błędy sprawdzania poprawności roszczeń czasowych, które często wchodzą w interakcję z przepływami odświeżania, można znaleźć w artykule JWT typowe błędy exp/iat/nbf.
FAQ
Jak powinienem obsługiwać jednoczesne żądania odświeżenia?
Użyj krótkiego okresu karencji (5–10 sekund), podczas którego poprzedni token odświeżania jest nadal akceptowany. Obsługuje to warunki wyścigu, gdy wiele wywołań API wyzwala jednocześnie odświeżenie. Po okresie karencji ważny jest tylko najnowszy token.
Czy tokeny odświeżania powinny być JWT czy ciągami nieprzezroczystymi?
Nieprzezroczyste ciągi znaków są ogólnie bezpieczniejsze w przypadku tokenów odświeżania. JWT przenoszą dane ładunku, które zwiększają powierzchnię ataku, a tokeny odświeżania nie muszą być samodzielne, ponieważ serwer i tak zawsze wyszukuje je w bazie danych.
Jak długo powinny trwać sesje odświeżania?
7–30 dni jest typowe. Aplikacje o wysokim poziomie bezpieczeństwa (bankowość, opieka zdrowotna) powinny zużywać 1–7 dni. Aplikacje konsumenckie mogą działać do 90 dni z rotacją. Zawsze łącz długie sesje z wykrywaniem odcisków palców urządzenia i wykrywaniem anomalii.
Powiązane narzędzia i artykuły
- Dekoder JWT — sprawdzaj tokeny i weryfikuj roszczenia czasowe
- Błędy bezpieczeństwa JWT — typowe pułapki JWT wykraczające poza tokeny odświeżania
- JWT Błędy związane z roszczeniami terminowymi — problemy z przesunięciem zegara i kolejnością walidacji
- 2FA Guide — wzmocnij uwierzytelnianie poza tokenami