Najpoważniejsze błędy JWT nie polegają na złym podziale stringa po kropkach. Pojawiają się, gdy system myli poprawny kryptograficznie token z tokenem zaufanym dla tego requestu. Podpis może być prawidłowy, ale issuer, audience, algorytm albo typ tokena nie pasują do endpointu. Weryfikacja musi być sztywną polityką, a nie próbą zaakceptowania możliwie wielu wariantów.

Header nie może wybierać polityki bezpieczeństwa

Token deklaruje alg, lecz aplikacja już wcześniej wie, co dopuszcza dla danego issuera. Historyczne ataki wykorzystywały none lub pomylenie algorytmu asymetrycznego z HMAC. Elastyczna biblioteka używała klucza w niewłaściwej roli.

Każdy typ tokena potrzebuje wąskiej allowlisty. Nieoczekiwany algorytm oznacza odrzucenie, a nie fallback.

Podpis bez walidacji claims jest niepełny

Po weryfikacji kryptograficznej trzeba sprawdzić expiry, issuer, audience, not-before i dopuszczalny clock skew. Znany provider może wystawić token dla innej aplikacji. Ten fakt nie czyni go ważnym tutaj.

Tenant, scope i token type również wymagają jawnej kontroli. Nie każdy custom claim ma takie samo znaczenie u wszystkich issuerów.

Słaby sekret HMAC można zgadywać offline

Atakujący posiada wiadomość i podpis, więc może lokalnie sprawdzać kandydatów na secret. Krótkie hasło konfiguracyjne jest złym kluczem. Potrzebna jest losowa, odpowiednio długa wartość przechowywana w secret managerze.

Podpis asymetryczny ogranicza dystrybucję private key. Usługi weryfikujące nie potrafią wtedy samodzielnie wystawiać tokenów.

Dowolne URL kluczy tworzą SSRF i zmianę zaufania

Niektóre headery potrafią wskazywać certyfikat lub key set. Weryfikator nie może pobierać dowolnego URL podanego przez atakującego. Mógłby połączyć się z siecią wewnętrzną albo zaakceptować klucz kontrolowany przez autora tokena.

Źródła kluczy są skonfigurowane dla issuera i ograniczone do znanych HTTPS endpoints. Obowiązują cache, limity i kontrolowana rotacja.

Kid pozostaje niezaufanym stringiem

Key ID nie powinien trafiać do SQL, ścieżki pliku czy komendy. Bezpieczna operacja to dokładne wyszukanie w mapie znanych kluczy. Nieznany identyfikator nie uruchamia dowolnej logiki.

Jednorazowe odświeżenie JWKS może być rozsądne, ale flood losowymi kid nie może zmusić usługi do ciągłego ruchu sieciowego.

Długi access token komplikuje incydent

Bearer token działa dla każdego posiadacza. Po kradzieży zmiana hasła nie zawsze unieważnia go automatycznie. Długi expiry powiększa okno wykorzystania i opóźnia odebranie roli.

Krótkie access tokens ograniczają szkodę. Refresh tokens wymagają rotacji, bezpiecznego storage i wykrywania ponownego użycia starego egzemplarza.

Logout musi mieć techniczną definicję

Usunięcie tokena w jednej przeglądarce nie wpływa na kopię atakującego ani inne urządzenie. Jeśli produkt obiecuje globalny logout, backend potrzebuje revocation, session version lub krótkiego czasu życia.

Interfejs nie powinien sugerować mocniejszej gwarancji niż architektura. Wymagana szybkość unieważnienia jest decyzją produktową i bezpieczeństwa.

Payload nie jest zaszyfrowany

E-mail, role i inne dane mogą trafić do DevTools, logów oraz monitoringu. Podpis nie ukrywa treści. Minimalny zestaw claims zmniejsza ryzyko prywatności i problem z nieaktualnymi informacjami.

Jeżeli serwer i tak ładuje bieżący profil, opaque session ID może być prostszym rozwiązaniem niż duży czytelny token.

Token w URL rozprzestrzenia się po systemach

Query jest zapisywane w historii, proxy, analityce i czasem Referer. Bearer token powinien używać Authorization header lub odpowiednio chronionego cookie. Jednorazowy token linku musi być ograniczony i usunięty po użyciu.

Pipeline logów powinien redagować nagłówki oraz cookies. Screenshot błędu nie może stać się wyciekiem credentials.

Browser storage zmienia model zagrożeń

Local Storage jest czytelny dla JavaScript, więc XSS może wyeksportować token. HttpOnly cookie chroni przed odczytem, ale automatyczny transport wymaga strategii CSRF, SameSite i wąskich atrybutów Domain oraz Path.

Backend-for-Frontend może przechowywać OAuth tokens po stronie serwera i dawać przeglądarce zwykłą sesję. Ogranicza to liczbę credentials dostępnych frontendowi.

Rola nie zastępuje autoryzacji obiektu

Claim admin nie mówi automatycznie, że użytkownik może zmienić każdy rekord w każdym tenant. Endpoint nadal sprawdza zasób, akcję i relację podmiotu.

Najbardziej dynamiczne decyzje powinny korzystać z aktualnych danych. Token jest snapshotem, nie żywym modelem uprawnień.

Telemetryka nie powinna kopiować tokena

Zewnętrzny błąd nie musi ujawniać algorytmu i klucza. Wewnętrznie można mierzyć kategorie: expired, wrong audience, unknown kid. Pełny token nie jest potrzebny.

Bezpieczny fingerprint lub jti pozwala korelować zdarzenia. Dashboardy nie stają się magazynem aktywnych poświadczeń.

Incydent z kluczem wymaga gotowego scenariusza

Po podejrzeniu wycieku private key nie wystarczy wygenerować nowego. Trzeba zatrzymać wydawanie tokenów starym kluczem, opublikować nowy zestaw, ocenić ważność istniejących credentials i zdecydować, czy wymusić ponowne logowanie. Czas życia access tokenów określa minimalne okno ryzyka bez dodatkowej revocation.

Logi powinny pozwalać ustalić, które kid i issuer były używane, ale nie mogą zawierać sekretów. Przećwiczona rotacja awaryjna jest częścią projektu, nie dokumentem tworzonym dopiero podczas ataku.

Wiele issuerów wymaga rozdzielonych konfiguracji

Łączenie kluczy kilku dostawców w jeden wspólny verifier zwiększa ryzyko pomylenia audience i semantyki claims. Każdy issuer powinien posiadać własne źródło kluczy, allowlistę algorytmów i mapowanie uprawnień.

Claim o tej samej nazwie może oznaczać coś innego u innego dostawcy. Normalizacja następuje dopiero po pełnej weryfikacji źródła.

Testy negatywne definiują bezpieczną granicę

Suite powinna obejmować zły issuer, audience, expiry, future nbf, zmieniony payload, nieznany kid i zabroniony algorytm. Rotacja wymaga jednoczesnego testu starych i nowych kluczy.

Bezpieczeństwo polega na akceptowaniu wyłącznie wąskiego zamierzonego przypadku. Weryfikator nie jest uniwersalnym czytnikiem dowolnych JWT.