JWT (JSON Web Token) to zwarty format do przesyłania podpisanych danych, najczęściej informacji o uwierzytelnionym użytkowniku. Token składa się z trzech części oddzielonych kropkami: header.payload.signature. W polskich firmach spotyka się go zarówno w projektach .NET i Java/Spring, jak i coraz częściej w Node.js czy Laravel w sektorze fintech.
Polskie znaki diakrytyczne w claims a rozmiar tokenu
Payload w stylu {"imie": "Łukasz Wiśniewski", "miasto": "Łódź"} koduje się do Base64URL dokładnie tak samo jak każdy inny JSON — proces operuje na bajtach UTF-8, niezależnie od języka. W praktyce oznacza to, że każda z dziewięciu polskich liter (ą, ć, ę, ł, ń, ó, ś, ź, ż) zajmuje 2 bajty zamiast jednego, więc token z prawdziwymi polskimi imionami i nazwami miast jest zauważalnie dłuższy niż jego angielski odpowiednik.
PESEL i dane wrażliwe w tokenie — pułapka do uniknięcia
Ponieważ header i payload JWT można zdekodować bez żadnego klucza, umieszczenie numeru PESEL, NIP czy innych danych wrażliwych bezpośrednio w claims oznacza w praktyce udostępnienie ich każdemu, kto przechwyci token — nawet jeśli podpis jest prawidłowy i nie do sfałszowania. Dobra praktyka w polskich systemach z RODO to trzymanie w tokenie wyłącznie identyfikatora użytkownika, a nie samych danych osobowych.
Trzy części tokenu
- Header — JSON zawierający typ tokenu i algorytm podpisu (np. HS256 lub RS256), zakodowany w Base64URL.
- Payload — JSON z „claims": danymi użytkownika, czasem wystawienia, wygaśnięciem itd., także w Base64URL.
- Signature — podpis obliczony na podstawie header i payload za pomocą tajnego lub prywatnego klucza, potwierdzający, że token nie został zmieniony.
Ważna różnica: dekodowanie ≠ weryfikacja
Header i payload to tylko Base64URL — każdy może je zdekodować i odczytać zawartość bez żadnego klucza. Zawartości tokenu można zaufać dopiero po zweryfikowaniu jego podpisu odpowiednim kluczem — a tę weryfikację wykonuje serwer, nie klient, który po prostu patrzy, co jest w środku tokenu.
Niebezpieczny atak: podmiana algorytmu na „none"
Specyfikacja JWT dopuszcza algorytm none — token bez podpisu. Jeśli backend naiwnie ufa polu alg z nagłówka tokenu zamiast weryfikować podpis stałym, znanym z góry algorytmem, atakujący może podmienić alg na none, usunąć podpis, a token przejdzie weryfikację z dowolnymi danymi. Solidne biblioteki JWT wymagają jawnego wskazania oczekiwanego algorytmu podczas weryfikacji.