Temat, któremu chcemy się dzisiaj przyjrzeć to JWT, ostatnio bardzo często wykorzystywany w kontekście autoryzacji. Przyjrzymy się dokładniej czym jest JSON Web Tokens oraz w jaki sposób go generować i wykorzystywać w rzeczywistych przypadkach.
JWT – co to jest?
JWT (JSON Web Tokens) to otwarty standard (RFC 7519), który definiuje sposób wymiany danych między stronami w bezpieczny sposób poprzez obiekt JSON. Przesyłane informacje mogą być weryfikowane dzięki cyfrowemu podpisowi, który jest elementem tokenu.
Token JWT jest podpisany za pomocą sygnatury – algorytmem HMAC lub za pomocą klucza publicznego/prywatnego RSA lub ECDSA.
Kiedy JSON Web Tokens?
JWT może być wykorzystany przy:
1. Autoryzacji – JWT znajduje szerokie zastosowanie w autoryzacji kiedy jedna ze stron chce przyznać dostęp drugiej do zasobów i serwisów, a później bez przechowywania stanu po swojej stronie weryfikować czy dostęp powinien być możliwy.
2. Transmisji danych – Kiedy chcemy przesłać pomiędzy stronami informacje i potrzebujemy mieć pewność, że nadawca jest tym za kogo się podaje i dane które wysyła nie zostały zmienione. Możemy to zweryfikować właśnie dzięki cyfrowemu podpisowi, które jest częścią JWT.
Struktura JWT
JWT w swojej wynikowej postaci (jako token) składa się z trzech części oddzielonych od siebie kropkami.
Przykład:
aaaa.bbbb.cccc
Te części to kolejno:
• Nagłówek (Header)
• Zawartość (Payload)
• Sygnatura (Signature)
1. Nagłówek (Header)
Nagłówek zawiera informację o rodzaju tokena – JWT oraz o tym jakiego algorytmu używamy – HMAC SHA256 lub RSA.
Przykład:
{ "alg": "HS512", "typ": "JWT" }
Obiekt JSON w postaci wynikowej jest zmieniany na zapis w Base64.
2. Zawartość (Payload)
Ta część odpowiedzialna jest za przechowywanie danych, które chcemy przesyłać w tokenie. JWT wyróżnia trzy typy informacji zawartych w payload: Registered claims, Public claims oraz Private claims.
Oprócz danych identyfikacyjnych tokena oraz informacji o dacie ważności i kontekstu, w payload umieszczamy dane związane z rolą użytkownika, dostępem do zasobów, ustawieniami itp.
Przykład:
{ "customerId": "123", "role": "customer" }
Tak jak w przypadku nagłówka, payload też kodowany jest w formacie Base64.
3. Sygnatura (Signature)
Sygnatura jest podpisem cyfrowym potwierdzającym autentyczność danych zawartych w tokenie. Walidacja sygnatury daje nam pewność, że nadawca jest tym za kogo się podaje.
Pewność tą zyskujemy dzięki metodzie budowania sygnatury. Przyjrzyjmy się temu bliżej:
Jeśli wybierzemy algorytm haszowania np. HMAC SHA256 to sygnatura tworzoną będzie w następujący sposób:
HMACSHA256(base64UrlEncode(header) + ’.’ + base64UrlEncode(payload), secret)
Gdzie secret to nasze hasło potrzebne do haszowania sygnatury. Musimy pamiętać o tym, że secret powinien być długi i składać się z różnych znaków, ponieważ łamiąc secret jesteśmy w stanie podszyć się pod serwis autoryzacyjny i wprowadzić swoje dane w payload.
Przykład implementacji algorytmu generowania tokenu JWT napisany w NodeJS. W przykładzie skorzystamy z implementacji algorytmu haszowania i kodowania base64Url poprzez zewnętrzne biblioteki.
const hmacSha256 = require('crypto-js/hmac-sha256'); const base64url = require('base64url'); const header = { typ: 'JWT', alg: 'HS256' }; const payload = { userId: 123, role: 'customer' }; const secret = 'secret password'; const jwtToken = base64UrlEncode(header) + '.' + base64UrlEncode(payload); const signature = base64url.encode(hmacSha256(jwtToken, secret).toString()); const jwtSignedToken = jwtToken + '.' + signature; console.log(jwtSignedToken); function base64UrlEncode(item) { return base64url.encode(JSON.stringify(item)); };
Zastosowanie
JSON Web Tokens można wykorzystać np. do budowy serwisu autoryzacyjnego, w którym chcemy uwierzytelniać użytkowników aplikacji – przykład:
Tworzenie serwisu z możliwością autoryzowania użytkowników:
1. Budujemy back-end naszej aplikacji i udostępniamy REST API naszym aplikacją klienckim.
2. Tworzymy aplikację kliencką, która komunikuję się poprzez REST API z częścią back-endową.
3. Dołączamy serwis autoryzacyjny, za pomocą którego aplikacje klienckie będą uzyskiwały tokeny JWT a back-end będzie w stanie sprawdzić czy użytkownik powinien dostać dostęp do żądanego zasobu.
Podsumowanie
W tym wpisie omówiliśmy strukturę JWT i zasadę budowania tokenów. Widzimy również zastosowanie tego standardu i w jak łatwy sposób jesteśmy w stanie zarządzać uprawnieniami i autoryzacją użytkowników.
Źródło: https://jwt.io/
Autorem tekstu jest Kamil Moroń.