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

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:
- exp (Czas ważności) — token NIE MOŻE zostać zaakceptowany po tym znaczniku czasu
- iat (Wydano w) — kiedy token został utworzony
- nbf (nie wcześniej) — token NIE MOŻE zostać zaakceptowany przed tym znacznikiem 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:
- Architektury mikrousług z niezsynchronizowanymi zegarami
- Funkcje bezserwerowe, w których kontenery mają dryf zegara
- Aplikacje mobilne, w których zegar urządzenia jest ustawiany ręcznie
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:
- Dekoduj nagłówek (algorytm sprawdzania)
- Zweryfikuj podpis
- Sprawdź
exp(odrzuć, jeśli wygasł) - Sprawdź
nbf(odrzuć, jeśli nie jest jeszcze ważny) - Sprawdź
iat(odrzuć, jeśli jest nieracjonalnie stary) - 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:
- Tokeny dostępu: 5–15 minut
- Odśwież tokeny: 7–30 dni (z rotacją)
- Tokeny ID: 1 godzina
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:
- Token z
expw przeszłości → 401 - Token z
expdokładnie teraz → 401 (granica) - Token bez
exp→ 401 - Token z
nbfw przyszłości → 401 - Token z
nbfnieznacznie w przyszłości (w granicach tolerancji) → 200 - Token z
iatw przyszłości → 401 (oznacza manipulację) - 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
- Dekoder JWT — sprawdź oświadczenia czasowe w dowolnym tokenie
- Błędy bezpieczeństwa JWT — szersze pułapki JWT wykraczające poza roszczenia związane z czasem
- Odśwież rotację tokena — bezpieczny wzorzec dla długotrwałych sesji
- 2FA Guide — dodaj drugą warstwę poza tokenami