JWT Authentication - podstawowe zagadnienia

Mateusz Gajda12/11/2018 - 2 min read

Photo by: Alvaro Reyes

JSON Web Token

JSON Web Token (JWT) to otwarty standard który definiuje bezpieczny sposób wymiany informacji w postaci obiektu JSON. Zawarty w nim cyfrowy podpis umożliwia nam jego zweryfikowania po uwcześniejszym podpisaniu go za pomocą algorytmu HMAC lub pary prywatnych/publicznych kluczy. Podpisane tokeny dają nam możliwość sprawdzenia, czy zawarte w nich informację są poprawne i prawdziwe. Jak i pozwalają stwierdzić, czy nie zostały zmienione. Najpopularniejszym sposobem wykorzystania tokenów jest autoryzacja użytkownika. Raz zalogowany użytkownik, za pomocą tokena jest w stanie potwierdzić swoją tożsamość i dostać się do odpowiednich dla siebie zasobów

Na szeroko pojętą kontrolę dostępu składają się trzy etapy:

  • Identyfikacja (ang. indentification) – jest to deklaracja przez użytkownika swojej tożsamości.
  • Uwierzytelnianie (ang. authentication)- jest to weryfikacja deklaracji użytkownika poprzez jakiś wewnętrzny mechanizm. Tu właśnie ten proces często nazywa się autentykacją, co z punktu widzenia języka polskiego jest formą niepoprawną (sam dostałem za to „baty” na uczelni).
  • Autoryzacja (ang. authorization) – jest to etap, w którym użytkownik został poprawnie „rozpoznany” jednak sprawdzane są jego uprawnienia do uzyskania żądanego zasobu.

Struktura JWT

header.payload.signature

Token jest zwykłym stringiem, składającym się z trzech elementów, rozdzielonych kropką. Każdy z nich ma swoją odpowiednią funkcję.

Header - w poniższym JSONie wartość klucza typ oznacza że mamy do czynienia z tokenem JWT. W przypadku klucza alg mamy informację o rodzaju algorytmu haszującego który został użyty do stworzenia sygnatury. W naszym przypadku jest to algorytm SHA256, który wykorzystuje secret key, aby obliczyć sygnaturę.

{
alg: HS256,
typ: JWT
}

Payload - kolejna częśc tokena zawiera w sobie informację (claim) , które chcemy umieścić wewnątrz tokena. Ilość informacji jest nieograniczona, możemy więc umieścić tam wszystko czego będziemy potrzebować. Warto jednak pamiętać że ilość danych, będzie bezpośrednio wpływała na rozmiar tokenu. Jeżeli przesadzimy, może się to negatywnie odbić na performance. Istnieje wiele różnych już zdefiniowanych claimów, takich jak iss (issuer), exp(expiration time) czy sub (subject).

Sygnatura - jest ostatnią częścią naszego tokena. Jest to zaszyfrowany header i payload naszego tokenu, za pomocą wcześniej zdefiniowanego przez nas algorytmu. Poniżej znajduje się pseudokod wyjaśniający w jaki sposób tworzony jest token. Za pomocą algorytmu base64url szyfrujemy osobno header i payload, a następnie łączymy je ze sobą, wstawiając między nimi kropkę. Całość przypisujemy do zmiennej data. Następnie osobno tworzymy sygnaturę, którą szyfrujemy za pomocą wcześniej zdefiniowanego w headerze algorytmu i base64url. Tak utworzoną sygnaturę, przypisujemy do wcześniej przygotowanej zmiennej data.

var headers = base64URLencode(myHeaders);
var payload = base64URLencode(myClaims);
var data = header + . + claims;
var signature = base64URLencode(HMACSHA256(payload, secret));
var encodedJWT = data + . + signature;

O czym należy pamiętać korzystając z JWT?

Najważniejsze w używaniu JWT jest weryfikowanie tokenu, którym użytkownik się uwierzytelnia. Za każdym razem musimy sprawdzać czy token, który dostaliśmy do autentykacji na pewno jest wystawiony przez nas. Klucz którego używamy do szyfrowania, powinien znajdować się jedynie po stronie serwera naszej aplikacji, lub serwera odpowiedzialnego za autentykację. Dzięki temu będziemy mieli pewność, że nikt w ten sam sposób nie podpisze podrobionego tokena. My sami będziemy mogli w łatwy sposób odtworzyć token i sprawdzić czy został on wystawiony właśnie przez nas.

Warto również pamiętać że payload nie jest w żaden sposób przez nas zabezpieczony. Nie trzymajmy więc tam żadnych wrażliwych danych, które mogą posłużyć do wycieku informacji z naszej aplikacji. Warto również ograniczyć czas życia tokenu, by mieć pewność że w razie jego wycieku, jego zdolności nie będą trwały zbyt długo.

Podsumowując

Ten wpis to tak naprawdę liźnięcie tematu tokenów. Zobaczyliśmy w jaki sposób są one tworzone, oraz z jakich części się składają. Warto również zaznaczyć że w celu podniesienia bezpieczeństwa wymiany tokenami między serwerem a użytkownikiem, zawsze powinniśmy stosować połączenie HTTPS. Pozwoli nam to uniknąć sytuacji, gdzie nieuprawniona do tego osoba, wejdzie w posiadanie tokena jednego z naszych użytkowników.