Jeśli potrafisz zdekodować JWT, w jaki sposób są one bezpieczne?

302

Jeśli otrzymam JWT i mogę dekodować ładunek, jak to jest bezpieczne? Czy nie mogę po prostu wyciągnąć tokena z nagłówka, zdekodować i zmienić informacje o użytkowniku w ładunku i odesłać go z tym samym poprawnym, zakodowanym sekretem?

Wiem, że muszą być bezpieczne, ale naprawdę chciałbym zrozumieć technologie. czego mi brakuje?

PixMach
źródło
1
md5('original messaged' + secret) != md5('changed message' + secret)więc jeśli ktoś zmieni wiadomość, możesz ją wykryć
Pithikos,
prawda dla idealnego przypadku, jednak md5 ma kolizje. @Pithikos
Yash Kumar Verma
@YashKumarVerma tak, to tylko wykazanie istoty, ponieważ wszyscy znają md5.
Pithikos
@Pithikos, skąd znasz oryginalną wiadomość?
user1955934
1
@ user1955934 jest zakodowany w standardzie base64, NIE jest szyfrowany. Możesz po prostu zdekodować go za pomocą dowolnego dekodera base64.
Pithikos

Odpowiedzi:

386

JWT mogą być podpisane, zaszyfrowane lub oba jednocześnie. Jeśli token jest podpisany, ale nie zaszyfrowany, każdy może odczytać jego zawartość, ale gdy nie znasz klucza prywatnego, nie możesz go zmienić. W przeciwnym razie odbiorca zauważy, że podpis nie będzie już zgodny.

Odpowiedz na twój komentarz: Nie jestem pewien, czy rozumiem twój komentarz we właściwy sposób. Dla pewności: czy znasz i rozumiesz podpisy cyfrowe? Wyjaśnię krótko jeden wariant (HMAC, który jest symetryczny, ale jest wiele innych).

Załóżmy, że Alice chce wysłać JWT do Boba. Oboje znają jakiś wspólny sekret. Mallory nie zna tej tajemnicy, ale chce ingerować i zmieniać JWT. Aby temu zapobiec, Alice oblicza Hash(payload + secret)i dołącza to jako podpis.

Po otrzymaniu wiadomości Bob może również obliczyć, Hash(payload + secret)aby sprawdzić, czy podpis pasuje. Jeśli jednak Mallory coś zmieni w treści, nie będzie w stanie obliczyć pasującego podpisu (co byłobyHash(newContent + secret) ). Nie zna tajemnicy i nie ma sposobu, aby ją znaleźć. Oznacza to, że jeśli coś zmieni, sygnatura nie będzie już zgodna, a Bob po prostu nie zaakceptuje JWT.

Załóżmy, że wysyłam innej osobie wiadomość {"id":1}i podpisuję ją Hash(content + secret). (+ to tylko konkatenacja tutaj). Korzystać z funkcji SHA256 ziemniaczane i podpis pojawia się: 330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c. Teraz twoja kolej: wciel się w Mallory i spróbuj podpisać wiadomość {"id":2}. Nie możesz, bo nie wiesz, którego sekretu użyłem. Jeśli podejrzewam, że odbiorca zna sekret, MOŻE obliczyć podpis każdej wiadomości i sprawdzić, czy jest poprawny.

Misch
źródło
8
Więc podpis jest zmieniany, gdy zmienia się ładunek? Miałem wrażenie, że token ma format [nagłówek]. [Ładunek]. [Podpis] czy podpis jest obliczany na podstawie kombinacji ładunku i tajności? Gdyby tak było, to czy ładunek o innym identyfikatorze nie byłby taki sam dla tego sekretu? Tak jakby dane były {id: 1} i służyły do ​​obliczania części podpisu tokena z kluczem tajnym, czy nie oznaczałoby to, że {id: 2} będzie poprawny dla użytkownika 2, a więc użytkownik 1 mógłby się zmienić id do 2, a token byłby taki sam?
PixMach,
7
Dałem ci przykład, aby wszystko było jeszcze jaśniejsze, ale nie wyjaśnię ci całej koncepcji podpisów cyfrowych i HMAC. Przeczytaj o tych rzeczach, jest wiele materiałów wyjaśniających to.
Misch
11
Oh teraz rozumiem. Nie wiem, dlaczego brakowało mi pomysłu, że tajny skrót nie byłby poprawny po zmianie ładunku, ponieważ tajny skrót musiałby zostać ponownie obliczony. Z jakiegoś powodu nadal myślałem, że jest niezależny. Ten ostatni kawałek naprawdę wywiercił dla mnie to w domu. Dzięki, że mnie przez to przeprowadziłeś.
PixMach
30
Mam powiązane pytanie. Co uniemożliwia komuś podszywanie się pod Alice za pomocą skopiowanego JWT?
Morrowless
25
Jeśli ktoś ma JWT, może podszyć się pod Alice. Musisz więc uważać, jak je przechowywać i wysyłać. Należy również ustawić termin ważności w ładunku. W ten sposób, jeśli ktoś ukradnie JWT, ma ograniczony czas na jego użycie. Spójrz na stormpath.com/blog/…
Geraint Anderson
134

Możesz przejść do jwt.io, wkleić token i przeczytać zawartość. To początkowo denerwuje wielu ludzi.

Krótka odpowiedź brzmi: JWT nie zajmuje się szyfrowaniem. Dba o walidację. Oznacza to, że zawsze może uzyskać odpowiedź na „Czy zmieniono treść tego tokena”? Oznacza to, że manipulowanie tokenem JWT przez użytkownika jest daremne, ponieważ serwer będzie wiedział i zignorował token. Serwer dodaje podpis oparty na ładunku podczas wydawania tokena klientowi. Później weryfikuje ładowność i pasujący podpis.

Logiczne pytanie brzmi: jaka jest motywacja, aby nie zajmować się zaszyfrowanymi treściami?

  1. Najprostszym powodem jest założenie, że jest to w większości rozwiązany problem. Jeśli masz do czynienia z klientem takim jak na przykład przeglądarka internetowa, możesz przechowywać tokeny JWT w pliku cookie, który jest secure(nie jest przesyłany przez HTTP, tylko przez HTTPS) i httpOnly(nie może być odczytany przez Javascript) i rozmawia z serwerem przez szyfrowany kanał (HTTPS). Gdy wiesz, że masz bezpieczny kanał między serwerem a klientem, możesz bezpiecznie wymieniać JWT lub cokolwiek innego.

  2. To sprawia, że ​​sprawa jest prosta. Prosta implementacja ułatwia adopcję, ale pozwala również każdej warstwie robić to, co najlepiej (niech HTTPS obsługuje szyfrowanie).

  3. JWT nie jest przeznaczony do przechowywania poufnych danych. Gdy serwer otrzyma token JWT i potwierdzi go, można wyszukać ID użytkownika we własnej bazie danych w celu uzyskania dodatkowych informacji dla tego użytkownika (takich jak uprawnienia, adres pocztowy itp.). Dzięki temu JWT ma niewielkie rozmiary i pozwala uniknąć przypadkowego wycieku informacji, ponieważ wszyscy wiedzą, że nie należy przechowywać poufnych danych w JWT.

Nie różni się zbytnio od sposobu działania samych plików cookie. Pliki cookie często zawierają niezaszyfrowane ładunki. Jeśli używasz HTTPS, wszystko jest w porządku. Jeśli tak nie jest, wskazane jest szyfrowanie poufnych plików cookie. Nieprzestrzeganie tego oznacza, że ​​możliwy jest atak typu man-in-the-middle - serwer proxy lub dostawca usług internetowych odczytuje pliki cookie, a następnie odtwarza je później, udając, że jesteś tobą. Z podobnych powodów JWT należy zawsze wymieniać na bezpieczną warstwę, taką jak HTTPS.

aleemb
źródło
4
Pamiętaj! JWT należy zawsze wymieniać na bezpieczną warstwę, taką jak HTTPS
kodemirror
Ale jeśli JWT jest bezpieczny tylko przez HTTPS, dlaczego po prostu nie wysłać ładunku? POST -> nazwa użytkownika, hasło. Nadal jest szyfrowany, prawda?
GeekPeek
@GeekPeek za to, że powinieneś przeczytać o podstawach JWT, ale Session Auth, jak wspomniałeś, często wystarczy. JWT oferuje kilka innych korzyści, ale powoduje pewne kompromisy webskeleton.com/webdev/2019/10/22/…
aleemb
17

Zawartość tokena internetowego Json (JWT) nie jest z natury bezpieczna, ale ma wbudowaną funkcję weryfikacji autentyczności tokena. JWT to trzy skróty oddzielone kropkami. Trzeci to podpis. W systemie klucza publicznego / prywatnego wystawca podpisuje podpis tokena kluczem prywatnym, który można zweryfikować tylko za pomocą odpowiedniego klucza publicznego.

Ważne jest, aby zrozumieć różnicę między emitentem a weryfikatorem. Odbiorca tokena jest odpowiedzialny za jego weryfikację.

Istnieją dwa krytyczne kroki w bezpiecznym korzystaniu z JWT w aplikacji internetowej: 1) wysyłaj je zaszyfrowanym kanałem i 2) weryfikuj podpis natychmiast po jego otrzymaniu. Asymetryczny charakter kryptografii klucza publicznego umożliwia weryfikację podpisu JWT. Klucz publiczny sprawdza, czy JWT został podpisany przez odpowiadający mu klucz prywatny. Żadna inna kombinacja kluczy nie może wykonać tej weryfikacji, zapobiegając w ten sposób próbom podszywania się. Wykonaj te dwa kroki, a my z matematyczną pewnością możemy zagwarantować autentyczność JWT.

Więcej informacji: Jak klucz publiczny weryfikuje podpis?

ThisClark
źródło
2

Od samego początku dyskutujmy:

JWT to bardzo nowoczesne, proste i bezpieczne podejście, które obejmuje także tokeny Json Web. Tokeny internetowe Json to bezpaństwowe rozwiązanie do uwierzytelniania. Nie ma więc potrzeby przechowywania żadnego stanu sesji na serwerze, co oczywiście jest idealne dla spokojnych interfejsów API. Spokojne interfejsy API powinny zawsze być bezstanowe, a najczęściej stosowaną alternatywą dla uwierzytelniania za pomocą JWT jest po prostu przechowywanie stanu logowania użytkownika na serwerze za pomocą sesji. Ale oczywiście nie jest to zgodne z zasadą mówiącą, że uspokajające interfejsy API powinny być bezstanowe i dlatego rozwiązania takie jak JWT stały się popularne i skuteczne.

Teraz dowiedzmy się, jak uwierzytelnianie faktycznie działa z tokenami Json Web. Zakładając, że mamy już zarejestrowanego użytkownika w naszej bazie danych. Tak więc klient użytkownika zaczyna od wysłania żądania postu z nazwą użytkownika i hasłem, aplikacja sprawdza następnie, czy użytkownik istnieje i czy hasło jest poprawne, a następnie aplikacja wygeneruje unikalny token Json Web tylko dla tego użytkownika.

Token jest tworzony przy użyciu tajnego ciąg , który jest przechowywany na serwerze . Następnie serwer wysyła ten JWT z powrotem do klienta, który zapisze go w pliku cookie lub w lokalnej pamięci. wprowadź opis zdjęcia tutaj

W ten sposób użytkownik jest uwierzytelniany i zasadniczo zalogowany do naszej aplikacji bez pozostawiania żadnego stanu na serwerze.

Tak więc serwer nie wie, który użytkownik jest faktycznie zalogowany, ale oczywiście użytkownik wie, że jest zalogowany, ponieważ ma ważny token Json Web, który jest trochę jak paszport umożliwiający dostęp do chronionych części aplikacji.

Więc ponownie, aby upewnić się, że masz pomysł. Użytkownik jest zalogowany, gdy tylko odzyska swój unikalny ważny Json Web Token, który nie jest zapisany nigdzie na serwerze. Dlatego proces ten jest całkowicie bezpaństwowy.

Następnie za każdym razem, gdy użytkownik chce uzyskać dostęp do chronionej trasy, na przykład danych swojego profilu użytkownika. Wysyła swój Json Web Token wraz z prośbą, więc to trochę jak pokazanie swojego paszportu, aby uzyskać dostęp do tej trasy.

Gdy żądanie trafi na serwer, nasza aplikacja sprawdzi, czy token sieci Web Jsona jest rzeczywiście prawidłowy, a jeśli użytkownik naprawdę jest tym, za kogo się podaje, dobrze, wtedy żądane dane zostaną wysłane do klienta, a jeśli nie, to nastąpi być błędem informującym użytkownika, że ​​nie ma on dostępu do tego zasobu. wprowadź opis zdjęcia tutaj

Cała ta komunikacja musi odbywać się przez https, więc bezpieczny szyfrowany HTTP, aby uniemożliwić każdemu dostęp do haseł lub tokenów Json Web. Tylko wtedy mamy naprawdę bezpieczny system.

wprowadź opis zdjęcia tutaj

Tak więc token WWW Jsona wygląda jak lewa część tego zrzutu ekranu, który został pobrany z debugera JWT na stronie jwt.io. Zasadniczo jest to ciąg kodujący złożony z trzech części. Nagłówek, ładunek i podpis Teraz nagłówek to tylko niektóre metadane dotyczące samego tokena, a ładunek to dane, które możemy zakodować w tokenie, dowolne dane, które naprawdę chcemy. Im więcej danych chcemy tutaj zakodować, tym większy JWT. W każdym razie te dwie części są zwykłym tekstem, który zostanie zakodowany, ale nie zaszyfrowany.

Aby każdy mógł je odkodować i odczytać , nie możemy przechowywać tutaj żadnych wrażliwych danych. Ale to wcale nie jest problem, ponieważ w trzeciej części, a więc w podpisie, rzeczy naprawdę stają się interesujące. Podpis jest tworzony przy użyciu nagłówka, ładunku i klucza tajnego zapisanego na serwerze.

Cały proces nazywany jest podpisywaniem tokenu internetowego Json . Algorytm podpisywania pobiera nagłówek, ładunek i klucz tajny, aby utworzyć unikalny podpis. Więc tylko te dane plus sekret mogą stworzyć ten podpis, dobrze? Następnie wraz z nagłówkiem i ładunkiem podpis ten tworzy JWT, który następnie jest wysyłany do klienta. wprowadź opis zdjęcia tutaj

Gdy serwer otrzyma JWT w celu udzielenia dostępu do chronionej trasy, musi go zweryfikować, aby ustalić, czy użytkownik naprawdę jest tym, za kogo się podaje. Innymi słowy, sprawdzi, czy nikt nie zmienił nagłówka i danych ładunku tokena. Zatem ponownie, ten krok weryfikacji sprawdzi, czy żadna strona trzecia nie zmieniła ani nagłówka, ani ładunku tokenu Json Web.

Jak zatem działa ta weryfikacja? Cóż, w rzeczywistości jest to całkiem proste. Po otrzymaniu JWT weryfikacja zajmie jego nagłówek i ładunek, a wraz z kluczem tajnym, który jest nadal zapisywany na serwerze, w zasadzie tworzy podpis testowy.

Ale oryginalny podpis, który został wygenerowany przy pierwszym tworzeniu JWT, wciąż znajduje się w tokenie, prawda? I to jest klucz do tej weryfikacji. Ponieważ teraz wszystko, co musimy zrobić, to porównać podpis testowy z podpisem oryginalnym. A jeśli podpis testowy jest taki sam jak podpis oryginalny, oznacza to, że ładunek i nagłówek nie zostały zmodyfikowane. wprowadź opis zdjęcia tutaj

Ponieważ gdyby zostały zmodyfikowane, podpis testowy musiałby być inny. Dlatego w tym przypadku, gdy nie nastąpiła zmiana danych, możemy następnie uwierzytelnić użytkownika. I oczywiście, jeśli te dwa podpisy są faktycznie różne, to znaczy, że ktoś manipulował danymi. Zwykle poprzez zmianę ładunku. Ale ta osoba trzecia manipulująca ładunkiem nie ma oczywiście dostępu do tajemnicy, więc nie mogą podpisać JWT. Oryginalny podpis nigdy nie będzie odpowiadał zmanipulowanym danym. Dlatego weryfikacja zawsze zakończy się niepowodzeniem. I to jest klucz do uruchomienia całego systemu. To magia sprawia, że ​​JWT jest tak proste, ale także niezwykle potężne.

Lord
źródło
1

Tylko prywatny klucz JWT, który znajduje się na twoim serwerze, odszyfruje zaszyfrowany JWT. Ci, którzy znają privateKey, będą mogli odszyfrować zaszyfrowany JWT.

Ukryj klucz prywatny w bezpiecznej lokalizacji na serwerze i nigdy nie mów nikomu o kluczu prywatnym.

sdfdsf sdf
źródło
1
JWT nie zawsze są szyfrowane. Można je podpisać, zaszyfrować, podpisać, a następnie zaszyfrować lub zaszyfrować, a następnie podpisać.
csauve
0

Dla osób, które nie mogą sobie pozwolić na drogie zapytania do bazy danych, tak jak ja, jedną z opcji zachowania poufnych danych (przywilejów użytkownika itp.) Jest to, że podczas generowania JWT możesz zaszyfrować te dane i dołączyć je do tokena JWT. (Zachowaj klucz szyfrowania w wewnętrznej bazie danych)

Jeśli chcesz odczytać poufne informacje, możesz wysłać token JWT do wewnętrznej bazy danych i odszyfrować je, a następnie odzyskać informacje. W ten sposób nie musisz przeprowadzać wyszukiwania DB ani mieć poufnych informacji nagich w interfejsie za pomocą tokena JWT

Nirojan Selvanathan
źródło
-1

Sugerowałbym przyjrzenie się JWE przy użyciu specjalnych algorytmów, których nie ma w pliku jwt.io do deszyfrowania

Link referencyjny: https://www.npmjs.com/package/node-webtokens

jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
  jwt.parse(token).verify(pwd, (error, parsedToken) => {
    // other statements
  });
});

Ta odpowiedź może być za późno lub być może już znalazłeś drogę, ale nadal uważam, że byłaby pomocna dla ciebie i innych.

Prosty przykład, który stworzyłem: https://github.com/hansiemithun/jwe-example

Mithun Shreevatsa
źródło