← Powrót do bloga

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

Bezpieczeństwo programistów28 marca 2026·9 min czytania
JWT refresh token rotation diagram

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:

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:

  1. Sprawdź skrót tokena w bazie danych
  2. Sprawdź, czy należy do aktywnej rodziny i nie jest oznaczony jako used
  3. Oznacz jako used: true
  4. Wydaj nowy token odświeżenia (nowa losowa wartość, ta sama family_id)
  5. Wydaj nowy token dostępu
  6. 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:

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:

Token odświeżenia a token dostępu: skrócona instrukcja

WłaściwośćToken dostępuOdśwież token
Czas życia5–15 minut7–30 dni
FormatJWT (samodzielny)Nieprzezroczysty ciąg (zalecany)
PrzechowywaniePamięć (zmienna JS)httpTylko plik cookie
Wysłano doserwery APITylko serwer autoryzacji
ObrótNie potrzebnePrzy 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