Czym Jest JWT i Jak Bezpiecznie Go Zdekodować
JSON Web Tokeny pojawiają się wszędzie w nowoczesnym rozwoju webowym - nagłówki uwierzytelniania, przepływy OAuth, klucze API, zarządzanie sesją. Jeśli pracowałeś z dowolnym API wymagającym tokena Bearer, już użyłeś JWT. Ale większość programistów traktuje je jak nieprzejrzyste plamy i rzadko zagląda do środka. Zrozumienie struktury JWT, co znaczy każda część i jak zdekodować jeden bez popełniania błędów bezpieczeństwa zajmuje około piętnastu minut. Ten przewodnik pokrywa to wszystko.
Anatomia JWT
Każdy JWT to string trzech segmentów zakodowanych Base64URL oddzielonych kropkami:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiZXhwIjoxNzQ3MDAwMDAwLCJpYXQiOjE3NDY5OTY0MDAsInNjb3BlIjoicmVhZDp1c2VycyJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c Format to nagłówek.payload.podpis. Każdy segment koduje inne informacje.
Nagłówek
Pierwszy segment to nagłówek. Zdekodowany, przykład powyżej staje się:
{
"alg": "RS256",
"typ": "JWT"
} alg określa algorytm użyty do podpisania tokena - RS256 oznacza RSA z SHA-256. typ identyfikuje typ tokena. Te dwa pola to minimum; niektóre tokeny zawierają też kid (key ID), aby powiedzieć weryfikatorowi, którego klucza publicznego użyć, gdy wiele kluczy jest w rotacji.
Payload
Drugi segment to payload - rzeczywiste dane. Zdekodowany:
{
"sub": "user_123",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": 1747000000,
"iat": 1746996400,
"scope": "read:users"
} Payload zawiera oświadczenia: stwierdzenia o encji, którą token reprezentuje. Niektóre oświadczenia są standaryzowane (zwane zarejestrowanymi oświadczeniami); inne są specyficzne dla aplikacji (zwane prywatnymi oświadczeniami). Payload jest zakodowany Base64URL, nie zaszyfrowany. Każdy, kto dostanie string tokena, może odczytać każde oświadczenie w nim.
Podpis
Trzeci segment to podpis. Jest produkowany przez wzięcie zakodowanego nagłówka i payloadu, połączenie ich kropką, następnie podpisanie wyniku tajnym kluczem lub kluczem prywatnym określonym w alg:
signature = sign(
base64url(header) + "." + base64url(payload),
secretOrPrivateKey
) Podpis pozwala każdej stronie z odpowiednim kluczem publicznym (lub tajnym kluczem, dla algorytmów symetrycznych) zweryfikować, że token został wydany przez zaufane źródło i że ani nagłówek, ani payload nie były modyfikowane po wydaniu. Pojedynczy zmieniony znak w payloadzie unieważnia podpis całkowicie.
Jak Zdekodować JWT
Dekodowanie różni się od weryfikacji. Dekodowanie po prostu odczytuje dane w tokenie. Weryfikacja potwierdza, że token jest autentyczny i niewygasły. Zawsze powinieneś weryfikować w kodzie produkcyjnym; samo dekodowanie jest użyteczne do debugowania.
Krok 1: Podziel token
Podziel string JWT po znaku .. Dostaniesz trzy segmenty. Jeśli dostaniesz mniej niż trzy, token jest źle uformowany.
Krok 2: Zdekoduj nagłówek i payload
Base64URL dekoduj każdy z pierwszych dwóch segmentów. Base64URL jest jak standardowy Base64, ale używa - zamiast + i _ zamiast /, bez znaków paddingu. Po zdekodowaniu możesz sparsować każdy segment jako JSON.
Krok 3: Parsuj i sprawdzaj
Odczytaj oświadczenia. Sprawdź exp (wygaśnięcie) wobec bieżącego znacznika Unix. Spójrz na iss i aud, aby potwierdzić, że token jest przeznaczony dla twojej aplikacji. Nie ufaj żadnemu oświadczeniu, dopóki nie zweryfikujesz podpisu.
Do szybkiej inspekcji podczas rozwoju, użyj JWT Decoder. Działa całkowicie w twojej przeglądarce - twój token nigdy nie opuszcza twojego urządzenia. Możesz też dekodować segmenty base64 ręcznie koderem/dekoderem Base64, jeśli chcesz zobaczyć surowe bajty. Do weryfikowania podpisów w skryptach testowych, generator HMAC pozwala odtworzyć podpisy HS256 bez pisania kodu.
Krok 4: Zweryfikuj podpis w kodzie
W produkcji zawsze weryfikuj podpis używając biblioteki zbudowanej dla twojego języka. Nie implementuj weryfikacji podpisu ręcznie. Popularne opcje to jose lub jsonwebtoken dla Node.js, PyJWT dla Pythona, golang-jwt/jwt dla Go i nimbus-jose-jwt dla Java.
Zawsze przekazuj algorytm jawnie. Nigdy nie pozwalaj bibliotece wywnioskować algorytmu z nagłówka tokena.
Standardowe Oświadczenia (Zarejestrowane Oświadczenia)
RFC 7519 definiuje zestaw zarejestrowanych nazw oświadczeń. Nie są wymagane, ale gdy obecne, muszą podążać za standardową semantyką.
iss — Wydawca
Encja, która utworzyła i podpisała token. Zwykle URL identyfikujący serwer autoryzacji (na przykład https://auth.example.com). Weryfikatorzy powinni sprawdzać, że iss pasuje do oczekiwanej wartości, i odrzucać tokeny od nieznanych wydawców.
sub — Podmiot
Podmiot, który token reprezentuje - zwykle ID użytkownika, nazwa konta usługi lub identyfikator urządzenia. Wartość musi być unikalna w kontekście wydawcy. Twoja aplikacja używa sub do zidentyfikowania, do którego użytkownika należy żądanie.
aud — Odbiorca
Zamierzony odbiorca (odbiorcy) tokena. Jeśli identyfikator twojego API to https://api.example.com, tokeny wydane dla innych usług powinny być odrzucane. Niezwalidowanie aud pozwala atakującym ponownie używać tokena uzyskanego z jednej usługi w innej.
exp — Czas Wygaśnięcia
Znacznik czasu Unix, po którym token nie może być akceptowany. Zawsze waliduj exp. Token bez wygaśnięcia efektywnie żyje wiecznie - jeśli zostanie ukradziony, atakujący ma nieograniczony dostęp.
iat — Wydany W
Znacznik czasu Unix, kiedy token został utworzony. Użyteczne do wykrywania tokenów technicznie niewygasłych, ale podejrzanie starych. Możesz używać iat do wymuszania maksymalnego wieku tokena niezależnego od exp.
nbf — Nie Przed
Znacznik czasu Unix, przed którym token nie może być akceptowany. Mniej powszechne niż exp, ale użyteczne przy wydawaniu tokenów z wyprzedzeniem - na przykład zaplanowane zadanie, które nie powinno startować przed konkretnym czasem.
jti — JWT ID
Unikalny identyfikator dla tokena. Pozwala wydawcom zapobiegać atakom replay tokena, przechowując użyte wartości jti i odrzucając tokeny z duplikującymi się ID. Konieczne, gdy potrzebujesz tokenów jednorazowych, jak linki resetu hasła.
Pułapki Bezpieczeństwa
Implementacje JWT mają historię subtelnych podatności. To najważniejsze do zrozumienia przed wysyłaniem kodu akceptującego JWT.
Atak "alg: none"
Niektóre biblioteki JWT z wczesnych dni standardu akceptowały token określający "alg": "none" w swoim nagłówku. Atakujący mógł wziąć dowolny poprawny token, zastąpić algorytm none, usunąć podpis, a biblioteka akceptowała go jako w pełni poprawny - bez wymaganego podpisu.
Naprawa: zawsze określaj oczekiwany algorytm jawnie przy wywoływaniu swojej funkcji weryfikacji. Traktuj każdy token deklarujący alg: none jako niepoprawny. Większość nowoczesnych bibliotek zaadresowała to, ale warto potwierdzić domyślne ustawienia twojej biblioteki przed pójściem do produkcji.
Konfuzja Algorytmów (Downgrade RS256 do HS256)
Niektóre biblioteki obsługujące oba algorytmy używały pola alg w nagłówku tokena do decydowania, jak weryfikować. Atakujący mógł zmienić algorytm na HS256, następnie podpisać token używając publicznego klucza serwera jako sekretu HMAC. Serwer, widząc HS256, weryfikowałby wobec klucza publicznego i akceptował sfałszowany token.
Naprawa jest ta sama: zablokuj algorytm w kodzie weryfikacji. Nigdy nie pozwalaj nagłówkowi tokena wpływać na to, który algorytm jest używany do weryfikacji.
Akceptowanie Wygasłych Tokenów
Nie walidowanie exp to częste niedopatrzenie - czasami wprowadzane, gdy programiści dodają okres karencji rosnący bez granic, lub gdy ścieżka kodu walidacji jest pomijana w gałęzi kodu. Traktuj wygasły token tak samo jak brakujący token: odrzuć go z 401 i wymagaj od klienta ponownego uwierzytelnienia lub użycia tokena odświeżającego.
Wrażliwe Dane w Payloadzie
Payload jest zakodowany Base64URL, nie zaszyfrowany. Każdy, kto przechwyci token, może go zdekodować. Nie umieszczaj haseł, numerów kart kredytowych, numerów ubezpieczenia społecznego ani innych wrażliwych danych w payloadzie. Jeśli musisz przekazywać wrażliwe oświadczenia bezpiecznie, użyj tokena JWE (JSON Web Encryption) szyfrującego payload. JWT podpisane JWS (typowy przypadek) gwarantują tylko autentyczność, nie poufność.
Brakująca Walidacja Odbiorcy
Pomijanie walidacji aud oznacza, że token wydany dla Usługi A może być powtórzony w Usłudze B - dopóki obie usługi dzielą ten sam klucz podpisywania lub ufają temu samemu wydawcy. W architekturach wielousługowych zawsze waliduj, że odbiorca tokena pasuje do identyfikatora twojej usługi.
Najlepsze Praktyki na 2026
Wybieraj RS256 dla Większości Aplikacji
RS256 używa klucza prywatnego do podpisywania i klucza publicznego do weryfikacji. Tylko serwer autoryzacji trzyma klucz prywatny. Każda usługa może weryfikować tokeny używając klucza publicznego, który może być publikowany otwarcie (często przez endpoint JWKS). Jeśli jakakolwiek pojedyncza usługa zostanie skompromitowana, atakujący zyskują zdolność weryfikowania tokenów - ale nie fałszowania nowych.
HS256 używa pojedynczego współdzielonego sekretu zarówno do podpisywania, jak i weryfikacji. Każda usługa, która może weryfikować tokeny, może też je tworzyć. W konfiguracji mikroserwisów dzielenie sekretu między wieloma usługami zwiększa promień rażenia naruszenia.
Trzymaj Tokeny Dostępu Krótkotrwałymi
Nie ma wbudowanego mechanizmu unieważniania dla JWT - gdy raz wydany, token jest poprawny dopóki nie wygaśnie (chyba że zaimplementujesz blocklist, co ponownie wprowadza stan po stronie serwera). Krótkie czasy wygaśnięcia (15 minut do 1 godziny) ograniczają okno szkody, jeśli token zostanie ukradziony. Połącz tokeny dostępu z długotrwałymi tokenami odświeżającymi przechowywanymi w bezpiecznych ciasteczkach HttpOnly, nie w localStorage.
Używaj Rotacji Tokenów Odświeżających
Gdy klient używa tokena odświeżającego do uzyskania nowego tokena dostępu, wydaj nowy token odświeżający i unieważnij stary. W ten sposób ukradziony token odświeżający jest wykrywany następnym razem, gdy legalny klient próbuje użyć oryginalnego: serwer widzi ponownie użyty token odświeżający i może unieważnić całą sesję. Ten wzorzec jest opisany w RFC 6819 i jest szeroko obsługiwany przez nowoczesne serwery autoryzacji.
Publikuj Endpoint JWKS
Endpoint JSON Web Key Set (JWKS) (/.well-known/jwks.json z konwencji) publikuje twoje klucze publiczne podpisywania w standardowym formacie. Inne usługi mogą pobierać JWKS i weryfikować tokeny bez otrzymywania kluczy poza pasmem. To czyni też rotację kluczy prostą: dodaj nowy klucz do JWKS, zacznij podpisywać nim, następnie usuń stary klucz, gdy wszystkie istniejące tokeny wygasną.
Rotuj Klucze Okresowo
Nawet jeśli twój klucz prywatny nigdy nie zostanie skompromitowany, okresowa rotacja kluczy ogranicza okno, podczas którego ukradziony klucz mógłby być używany do fałszowania tokenów. Używaj kid w nagłówkach JWT, aby referencjonować klucz podpisywania, więc weryfikatorzy mogą wybrać właściwy klucz publiczny z twojego JWKS bez psucia istniejących tokenów podczas rotacji.
Waliduj Każde Oświadczenie
Sprawdzaj iss, aud, exp i nbf na każdym żądaniu. Nie pomijaj żadnego z nich, bo wydają się redundantne w twojej konfiguracji - warunki czyniące je pozornie niepotrzebnymi dziś to dokładnie warunki, które zmieniają się podczas incydentu.
JWT vs. Ciasteczka Sesji
JWT i sesje po stronie serwera rozwiązują ten sam problem - utrwalanie stanu uwierzytelniania przez bezstanowy HTTP - ale z różnymi kompromisami.
JWT są samowystarczalne. Serwer nie musi zapytywać bazy danych, aby zwalidować żądanie. To czyni je atrakcyjnymi dla systemów rozproszonych i API konsumowanych przez klientów mobilnych lub stron trzecich. Wadą jest to, że unieważnienie wymaga blocklisty (co ponownie wprowadza stan po stronie serwera) lub tolerowania pozostałego życia skompromitowanego tokena.
Ciasteczka sesji są walidowane po stronie serwera. Serwer przechowuje stan sesji i może natychmiast unieważnić dostęp, usuwając sesję. Ciasteczka z flagami HttpOnly i Secure są chronione przed dostępem JavaScript i przechwyceniem sieciowym. Wadą jest to, że każde żądanie wymaga zapytania bazy danych, co może stać się wąskim gardłem w skali.
Dla tradycyjnych aplikacji webowych z stronami renderowanymi po stronie serwera i pojedynczym backendem, ciasteczka sesji pozostają solidnym i prostszym wyborem. Dla API konsumowanych przez wielu klientów, architektur mikroserwisów i aplikacji mobilnych, JWT z krótkim wygaśnięciem i rotacją tokena odświeżającego to bardziej praktyczna opcja.
Zdekoduj Swój Token
Najszybszy sposób inspekcji JWT to wklejenie go do JWT Decoder. Dzieli token, dekoduje nagłówek i payload, i renderuje oświadczenia w czytelnym formacie - wszystko bez wysyłania twojego tokena gdziekolwiek. Jeśli musisz kodować lub dekodować surowe stringi Base64URL ręcznie, koder/dekoder Base64 obsługuje zarówno warianty standardowy, jak i URL-safe. Do weryfikowania podpisów HMAC w skryptach testowych, generator HMAC pozwala odtworzyć podpis HS256 i porównać go z tym, co zawiera twój token.
Po pełną specyfikację, zobacz RFC 7519 (JWT) i interaktywne przykłady na jwt.io.