← Powrót do bloga

JWT Błędy exp/iat/nbf: błędy związane z roszczeniami czasowymi, które psują uwierzytelnianie

Bezpieczeństwo programistów27 marca 2026·8 min czytania
JWT time claims debugging

JWT oświadczenia czasowe — exp, iat i nbf — są zwodniczo proste. To po prostu uniksowe znaczniki czasu. Jednak powodują one jedne z najbardziej frustrujących błędów uwierzytelniania w środowisku produkcyjnym: tokeny, które wygasają zbyt wcześnie, tokeny, które działają na jednym serwerze, a nie na innym, oraz tokeny, które w ogóle nigdy nie wygasają.

W tym artykule opisano najczęstsze błędy dotyczące roszczeń czasowych, przyczyny ich występowania i sposoby ich naprawienia za pomocą bezpiecznych ustawień domyślnych.

Jak działają exp, iat i nbf

Każdy JWT może zawierać w swoim ładunku trzy roszczenia zależne od czasu:

Wszystkie trzy to daty numeryczne: liczba sekund od 1970-01-01T00:00:00Z (epoka Uniksa). Nie milisekundy – sekundy. Samo to rozróżnienie powoduje około 20% wszystkich błędów związanych z czasem JWT.

Użyj naszego Dekodera JWT, aby natychmiast sprawdzić roszczenia czasowe w dowolnym tokenie.

Błąd nr 1: Używanie milisekund zamiast sekund

JavaScript Date.now() zwraca milisekundy. Specyfikacja JWT wymaga sekund. Ustawienie exp na Date.now() + 3600000 tworzy token, który wygasa w roku 2089, a nie za godzinę.

// ŹLE — milisekundy
const exp = Date.now() + 3600000; // POPRAWNIE — sekundy
const exp = Math.floor(Date.now() / 1000) + 3600;

Większość bibliotek JWT obsługuje to wewnętrznie, ale jeśli tworzysz ładunki ręcznie, jest to pierwsza rzecz, którą należy sprawdzić.

Błąd nr 2: Brakujące doświadczenie Odbierz w całości

Jeśli zapomnisz ustawić exp, wiele bibliotek z radością utworzy token, który nigdy nie wygaśnie. Stanowi to zagrożenie bezpieczeństwa: token, który wyciekł, pozostaje ważny na zawsze.

Zawsze ustawiaj exp. Zawsze sprawdzaj poprawność na serwerze. Jeśli Twoja biblioteka domyślnie nie odrzuca tokenów bez exp, skonfiguruj ją tak, aby to robiła.

// Node.js jsonwebtoken — wymuszanie wygaśnięcia
jwt.verify(token, sekret, { maxAge: '1h' });

Błąd nr 3: Przesunięcie zegara między serwerami

Serwer A wystawia token o godzinie 14:00:00. Zegar Serwera B wskazuje 13:59:55 (5 sekund opóźnienia). Jeśli token ma nbf: 1711540800 (14:00:00), Serwer B odrzuca go jako „jeszcze nieważny”.

Jest to szczególnie powszechne w:

Poprawka

Pozwól na małą tolerancję zegara (zwaną także „swobodą działania”) — zazwyczaj 30–60 sekund:

// jsonwebtoken
jwt.verify(token, sekret, { clockTolerance: 30 }); // Jose (Node.js)
czekaj jwtVerify(token, klucz, { clockTolerance: '30s' });

Nigdy nie ustawiaj tolerancji powyżej 2 minut. Jeśli potrzebujesz więcej, napraw synchronizację NTP.

Błąd nr 4: Niewłaściwa kolejność walidacji

Właściwa kolejność walidacji ma znaczenie. Jeśli sprawdzisz podpis po sprawdzeniu daty wygaśnięcia, osoba atakująca może stworzyć token z przyszłym exp, który przejdzie kontrolę czasu, ale ma nieprawidłowy podpis.

Nakaz bezpiecznej walidacji:

  1. Dekoduj nagłówek (algorytm sprawdzania)
  2. Zweryfikuj podpis
  3. Sprawdź exp (odrzuć, jeśli wygasł)
  4. Sprawdź nbf (odrzuć, jeśli nie jest jeszcze ważny)
  5. Sprawdź iat (odrzuć, jeśli jest nieracjonalnie stary)
  6. Sprawdź wydawcę, odbiorców i inne roszczenia

Większość dobrze utrzymanych bibliotek radzi sobie z tym poprawnie, ale niestandardowe oprogramowanie pośrednie często robi to źle.

Błąd nr 5: Zamieszanie w strefie czasowej w iat

Sygnatury czasowe JWT są zawsze podawane w formacie UTC. Ale programiści czasami tworzą je przy użyciu czasu lokalnego:

// ŹLE — lokalna strefa czasowa
const iat = nowa data('2026-03-27T14:00:00').getTime() / 1000; // POPRAWNE — jawny UTC
const iat = nowa Data('2026-03-27T14:00:00Z').getTime() / 1000;

Bez przyrostka Z JavaScript interpretuje ciąg znaków w lokalnej strefie czasowej, co może przesunąć znacznik czasu o godziny.

Błąd nr 6: Akceptowanie tokenów bez czeku nbf

Oświadczenie nbf jest przydatne w przypadku tokenów opóźnionej aktywacji — na przykład tokenu, który powinien działać dopiero po zaplanowanym wdrożeniu. Jeśli Twój walidator zignoruje nbf, tokeny te będą mogły zostać wykorzystane przed zamierzonym czasem aktywacji.

Większość bibliotek domyślnie sprawdza poprawność nbf, ale sprawdź to w swojej konfiguracji, szczególnie w przypadku niestandardowego oprogramowania pośredniczącego.

Błąd nr 7: Zbyt długa data ważności

Ustawienie exp na 30 dni dla tokenu dostępu mija się z celem tokenów krótkotrwałych. Najlepsze praktyki:

Wzorce bezpiecznych tokenów odświeżania znajdziesz w naszym przewodniku na temat JWT rotacji tokenów odświeżania.

Przypadki testowe, które powinien mieć każdy interfejs API

Dodaj je do swojego zestawu testów, aby wcześnie wykryć błędy związane z przekroczeniem czasu:

  1. Token z exp w przeszłości → 401
  2. Token z exp dokładnie teraz → 401 (granica)
  3. Token bez exp → 401
  4. Token z nbf w przyszłości → 401
  5. Token z nbf nieznacznie w przyszłości (w granicach tolerancji) → 200
  6. Token z iat w przyszłości → 401 (oznacza manipulację)
  7. Token z milisekundowymi znacznikami czasu → 401 (wykrywa błąd ms/s)

Bezpieczne ustawienia domyślne dla popularnych frameworków

Node.js (jsonwebtoken)

jwt.sign(ładunek, sekret, { expiresIn: '15m' });
jwt.verify(token, sekret, { clockTolerance: 30, maxAge: '15m'
});

Python (PyJWT)

jwt.decode(token, klucz, algorytmy=['HS256'], luz=timedelta(sekundy=30), opcje={'require': ['exp', 'iat']})

Go (golang-jwt)

parser := jwt.NewParser( jwt.WithLeeway(30 * czas.Sekunda), jwt.WithValidMethods([]string{"HS256"}),
)

FAQ

Czy powinno to być obowiązkowe?

Chociaż specyfikacja JWT mówi, że iat jest opcjonalny, uczynienie go obowiązkowym pomaga w debugowaniu i ścieżkach audytu. Bez iat nie można określić, kiedy token został utworzony, co utrudnia korelację ze zdarzeniami bezpieczeństwa.

Na jakie przesunięcie zegara powinienem pozwolić?

Domyślny, powszechny bezpieczny czas to 30–60 sekund. Więcej niż 2 minuty stwarza zagrożenie bezpieczeństwa. Jeśli Twoje systemy wymagają więcej, napraw synchronizację NTP zamiast zwiększać limit zniekształceń.

Jaki kod stanu HTTP powinienem zwrócić w przypadku tokena, który wygasł?

Return 401 Nieautoryzowany z wyraźną treścią błędu, np. {"error": "token_expired"}. Nie zwracaj 403 Forbidden — oznacza to, że token jest ważny, ale brakuje mu uprawnień, co jest inną sytuacją.

Powiązane narzędzia i artykuły