Wygasanie JWT i roszczenia "Issued-At": Jak uniksowe znaczniki czasu napędzają uwierzytelnianie tokenów

Roszczenia wygaśnięcia JWT exp i iat jako znaczniki czasu Unix w diagramie ładunku tokenu JSON

Za każdym razem, gdy użytkownik loguje się do aplikacji SaaS, generowany jest token uwierzytelniający i przekazywany do przeglądarki lub aplikacji mobilnej. Ten token zawiera w sobie ukryty zegar. Pole wygasania JWT , przechowywane jako zwykły Unix timestamp, informuje każdy serwer, który go odczytuje, kiedy dokładnie przestać ufać danemu poświadczeniu. Wystarczy błąd rzędu kilku sekund, a użytkownicy albo zostaną wylogowani zbyt wcześnie, albo - co gorsza - będą dysponować aktywną sesją znacznie dłużej, niż przewiduje polityka bezpieczeństwa. Zrozumienie, jak działają claimy JSON web token , a w szczególności exp i iat , to jedna z najbardziej praktycznych rzeczy, jaką zespół SaaS może zrobić, by wzmocnić uwierzytelnianie bez wprowadzania zbędnych utrudnień.

Najważniejsze wnioski:

  • Claimy exp i iat w JWT JSON web token to zawsze Unix timestampy wyrażone w pełnych sekundach, nie w milisekundach.
  • Różnica zegarów między serwerami może po cichu unieważniać tokeny lub wydłużać sesje ponad dopuszczalny limit - standardowym rozwiązaniem jest tolerancja 60 sekund.
  • Zbyt długi czas wygasania tokenu zwiększa ryzyko naruszenia bezpieczeństwa; zbyt krótki psuje doświadczenie użytkownika. Konkretna formuła pomoże wybrać właściwą wartość.
  • Możesz zdekodować i zweryfikować dowolny timestamp JSON web token w sekundach za pomocą konwertera epoki Unix - bez żadnej biblioteki.

Czym jest JWT i dlaczego timestampy są w nim przechowywane

JSON web token to kompaktowe, bezpieczne dla URL poświadczenie złożone z trzech części zakodowanych w Base64, oddzielonych kropkami: nagłówka, payloadu i podpisu. To właśnie w payloadzie przechowywane są dane wrażliwe na czas. Ponieważ JWT są bezstanowe, serwer nie sprawdza sesji w bazie danych podczas ich walidacji. Zamiast tego odczytuje claimy osadzone w payloadzie i ufa podpisowi kryptograficznemu. Takie podejście jest szybkie i skalowalne, ale niesie ze sobą istotne ograniczenie: raz wystawionego tokenu serwer nie może "usunąć". Jedynym niezawodnym sposobem ograniczenia jego czasu życia jest bezpośrednie osadzenie timestampu wygasania w samym tokenie.

Właśnie dlatego czas - a konkretnie czas epoki Unix - jest kluczowy dla bezpieczeństwa JWT. Specyfikacja RFC 7519 definiująca JWT wymaga, aby claimy związane z czasem były wyrażone jako wartości "NumericDate", czyli po prostu liczba sekund od 1 stycznia 1970 UTC. Bez stref czasowych. Bez formatowania regionalnego. Tylko liczba całkowita, którą każdy serwer na świecie może porównać z własnym zegarem.

Struktura JWT pokazująca nagłówek, payload i podpis z claimami exp i iat

Claimy exp i iat - wyjaśnienie

Specyfikacja JWT definiuje kilka zarejestrowanych claimów. Dwa z nich mają największe znaczenie dla zarządzania cyklem życia tokenu:

  • exp (Expiration Time - czas wygasania): Timestamp, po którym token nie może być akceptowany. Serwery są zobowiązane odrzucić każdy token, dla którego aktualny czas jest równy tej wartości lub ją przekracza. To podstawowy mechanizm wygasania JWT.
  • iat (Issued At - czas wystawienia): Timestamp wskazujący moment utworzenia tokenu. Claim iat nie jest domyślnie wymuszany, ale jest niezwykle przydatny. Pozwala obliczyć wiek tokenu, niezależnie od exp egzekwować politykę maksymalnego wieku oraz wykrywać tokeny wystawione podejrzanie dawno temu.

Trzeci claim, nbf (Not Before), określa najwcześniejszy moment, od którego token jest ważny. Jest rzadziej stosowany, ale używa tego samego formatu Unix timestamp.

Wszystkie trzy wartości są liczbami całkowitymi. Jeśli twój system generuje je w milisekundach - co jest częstym błędem przy użyciu Date.now() w JavaScript - wynikowa liczba będzie około 1000 razy większa niż oczekiwana. Serwer sprawdzający exp względem aktualnej sekundy epoki zobaczy token, który pozornie wygasa w roku 33 658 i nigdy go nie odrzuci. To realny błąd produkcyjny, który dotknął wiele zespołów SaaS.

Praktyczny przykład: dekodowanie timestampów z prawdziwego tokenu

Załóżmy, że twój serwis uwierzytelniania wystawia następujący payload JWT po zalogowaniu użytkownika o godzinie 10:00 UTC, 1 lipca 2025:

{
  "sub": "user_8821",
  "iat": 1751364000,
  "exp": 1751367600,
  "role": "admin"
}

Oto co oznaczają te liczby:

Claim Unix Timestamp Czytelna data (UTC) Znaczenie
iat 1751364000 2025-07-01 10:00:00 Token został wystawiony w tym momencie
exp 1751367600 2025-07-01 11:00:00 Token wygasa dokładnie godzinę później

Różnica wynosi dokładnie 3600 sekund, czyli jedną godzinę. Każdy serwer, który otrzyma ten token po godzinie 11:00:00 UTC, musi go odrzucić. Aby ręcznie to zweryfikować, wystarczy odjąć iat od exp : 1751367600 - 1751364000 = 3600 sekund. Czytelny odpowiednik dowolnej z tych wartości możesz natychmiast sprawdzić za pomocą konwertera Unix timestamp - to właśnie taki szybki test pozwala uniknąć wspomnianego wcześniej błędu z milisekundami zamiast sekund.

Więcej kontekstu na temat przechowywania tych wartości w bazach danych znajdziesz w naszym przewodniku o Unix timestampach w bazach danych - ten sam format całkowitoliczbowy obowiązuje zarówno przy zapisie exp w tokenie, jak i w tabeli z logiem audytowym.

Rozbieżność zegarów: cichy zabójca tokenów

To realne ograniczenie, które zaskakuje wiele zespołów. W systemie rozproszonym serwer uwierzytelniania i serwer API to dwie różne maszyny. Ich zegary systemowe są synchronizowane przez NTP, ale nigdy nie są idealnie zsynchronizowane. Różnica rzędu 30-90 sekund jest powszechna w środowiskach chmurowych.

Wyobraź sobie taki scenariusz: token z exp = 1751367600 jest walidowany przez serwer API, którego zegar wskazuje 1751367610 - zaledwie 10 sekund po wygasaniu. Token zostaje odrzucony. Użytkownik dostaje błąd 401. Z jego perspektywy właśnie się zalogował, a aplikacja przestała działać.

Standardowym rozwiązaniem jest wbudowanie tolerancji na rozbieżność zegarów w logikę walidacji. Większość bibliotek JWT obsługuje parametr leeway. Wartość 60 sekund jest powszechnie akceptowana i jest przywołana w specyfikacji OpenID Connect Core. Ustaw ją, udokumentuj i upewnij się, że każdy serwis w twoim stosie używa tej samej wartości.

Praktyczna zasada: Dodaj 60-sekundowy leeway do walidacji exp . Nigdy nie dodawaj leeway do sprawdzania iat , ponieważ pozwoliłoby to akceptować tokeny wystawione w przyszłości - co jest sygnałem ostrzegawczym dla ataków typu replay.

Jak dobrać właściwy czas wygasania tokenu dla swojego produktu SaaS

Właściwa wartość czasu wygasania tokenu zależy od wrażliwości twojej aplikacji i oczekiwanego zachowania sesji. Oto praktyczna ramka decyzyjna:

  • Aplikacje wysokiego ryzyka (bankowość, opieka zdrowotna, panele administracyjne): 15-30 minut dla tokenów dostępu. Używaj tokenów odświeżania do cichego odnawiania sesji.
  • Standardowe aplikacje SaaS (zarządzanie projektami, CRM, analityka): 1-8 godzin. Dopasuj do typowej długości sesji roboczej.
  • Niskoryzykowne lub tylko do odczytu API: Do 24 godzin, ale uzupełnij rotacją tokenów przy wrażliwych operacjach.
  • Tokeny serwisowe machine-to-machine: Mogą być dłuższe (dni lub tygodnie), ale powinny mieć wąski zakres uprawnień i być rotowane według harmonogramu.

Przydatna formuła do obliczania wartości exp w momencie wystawienia tokenu:

// Przykład w Node.js
const iat = Math.floor(Date.now() / 1000); // aktualny czas w sekundach
const ttl = 3600; // time-to-live: 1 godzina w sekundach
const exp = iat + ttl;

const payload = {
  sub: userId,
  iat: iat,
  exp: exp
};

Zwróć uwagę na jawne dzielenie przez 1000, które konwertuje milisekundy na sekundy. Ta jedna linia kodu zapobiega najczęstszemu błędowi z timestampami JWT w aplikacjach JavaScript.

Konkretne kroki do wdrożenia bezpiecznego wygasania JWT

Oto konkretna lista kontrolna, którą możesz zastosować w każdym systemie uwierzytelniania SaaS już dziś:

  1. Zawsze dołączaj zarówno iat , jak i exp . Claim iat jest technicznie opcjonalny, ale zapewnia ścieżkę audytu i umożliwia egzekwowanie maksymalnego wieku niezależnie od wygasania.
  2. Zweryfikuj format timestampu przed wdrożeniem. Zdekoduj token i sprawdź, czy exp jest 10-cyfrową liczbą całkowitą. Wartość 13-cyfrowa oznacza, że wkradły się milisekundy.
  3. Ustaw leeway rozbieżności zegarów na 60 sekund w swoim middleware walidacyjnym. Stosuj to konsekwentnie we wszystkich serwisach, które konsumują tokeny uwierzytelniające.
  4. Używaj krótkotrwałych tokenów dostępu z tokenami odświeżania. Token dostępu ważny 15 minut w połączeniu z 7-dniowym tokenem odświeżania jest znacznie bezpieczniejszy niż pojedynczy 7-dniowy token dostępu, ponieważ token odświeżania można unieważnić po stronie serwera.
  5. Loguj wartość iat przy każdym uwierzytelnionym żądaniu. Pozwala to wykrywać anomalie, takie jak użycie tego samego tokenu jednocześnie z dwóch różnych regionów geograficznych.
  6. Testuj wygasanie w środowisku staging z przyspieszonymi zegarami. Zasymuluj skok czasu poza wartość exp i upewnij się, że aplikacja obsługuje błąd 401 w sposób kontrolowany, a nie ulega awarii lub pętli.

Jeśli chcesz szybko przekonwertować surową wartość exp z tokenu na czytelną datę lub sprawdzić, jaki timestamp ustawić dla danego czasu trwania, konwerter epoki na naszej stronie głównej obsługuje oba kierunki natychmiast - bez żadnego kodu.

Podsumowanie

Wygasanie JWT to nie jest skomplikowana koncepcja, ale to obszar, w którym małe błędy tworzą poważne luki bezpieczeństwa. Claimy exp i iat to po prostu liczby całkowite - Unix timestampy liczone w sekundach od epoki. Ta prostota jest ich siłą: każdy serwer, każdy język programowania i każda platforma może porównać dwie liczby bez żadnych niejednoznaczności. Prawdziwa umiejętność polega na ich prawidłowym stosowaniu - wyborze sensownego czasu wygasania tokenu , obsłudze rozbieżności zegarów z odpowiednią tolerancją oraz wychwyceniu błędu milisekund kontra sekundy zanim trafi na produkcję. Wbuduj te nawyki w swój pipeline uwierzytelniania, a twoja implementacja JSON web token będzie zarówno bezpieczna, jak i łatwa w utrzymaniu.

Narzędzie do konwersji Unix timestamp do weryfikacji wygasania JWT

Weryfikuj timestampy JWT natychmiast - bez pisania kodu

Wklej dowolny Unix timestamp z payloadu JWT i jednym kliknięciem przekonwertuj go na czytelną datę. Wyłap błędy milisekund kontra sekundy zanim trafią na produkcję.

Wypróbuj nasze darmowe narzędzie →

exp (Expiration Time) to Unix timestamp, po którym token jest nieważny i musi zostać odrzucony. iat (Issued At) to timestamp wskazujący moment utworzenia tokenu. Obie wartości są liczbami całkowitymi w sekundach. Claim iat jest opcjonalny, ale przydatny do audytu i egzekwowania polityki maksymalnego wieku tokenu.

Unix timestampy to liczby całkowite niezależne od strefy czasowej, dzięki czemu są jednoznaczne na wszystkich serwerach i we wszystkich regionach. Sformatowane ciągi dat, takie jak "2025-07-01T10:00:00", mogą być błędnie interpretowane w zależności od ustawień regionalnych lub strefy czasowej. Porównanie liczb całkowitych jest też szybsze i mniej podatne na błędy niż parsowanie stringów w systemach uwierzytelniania o wysokiej przepustowości.

Długo żyjący token pozostaje ważny nawet jeśli konto użytkownika zostanie przejęte lub jego uprawnienia ulegną zmianie. Ponieważ JWT są bezstanowe, serwer nie może ich unieważnić w trakcie okresu ważności. Jeśli atakujący ukradnie token z 30-dniowym czasem wygasania, ma 30 dni dostępu. Krótkie okna wygasania w połączeniu z tokenami odświeżania znacznie redukują to ryzyko.

W JavaScript zawsze używaj Math.floor(Date.now() / 1000) przy generowaniu wartości iat lub exp . Surowe Date.now() zwraca milisekundy. Podzielenie przez 1000 konwertuje to na liczbę całkowitą w sekundach, której wymaga specyfikacja JWT. Zweryfikuj poprawność sprawdzając, czy twój timestamp ma 10 cyfr, a nie 13.

Rozbieżność zegarów to niewielka różnica czasu między zegarami systemowymi dwóch serwerów w systemie rozproszonym. Nawet 30-sekundowa różnica może spowodować odrzucenie ważnego tokenu, jeśli zegar serwera walidującego jest nieco do przodu. Standardowym rozwiązaniem jest skonfigurowanie 60-sekundowego leeway w bibliotece walidacji JWT, aby pochłonąć normalne dryfy NTP.