Co się stanie, jeśli JWT zostanie skradziony?


201

Próbuję zaimplementować bezstanowe uwierzytelnianie za pomocą JWT dla moich interfejsów API RESTful.

AFAIK, JWT jest w zasadzie zaszyfrowanym łańcuchem przekazywanym jako nagłówki HTTP podczas wywołania REST.

Ale co będzie, jeśli ktoś podsłuchujący zobaczy żądanie i ukradnie token ? Czy będzie mógł sfałszować prośbę z moją tożsamością?

W rzeczywistości dotyczy to wszystkich uwierzytelnień opartych na tokenach .

Jak temu zapobiec? Bezpieczny kanał, taki jak HTTPS?


1
Dlatego tokeny są często ważne tylko przez krótki okres czasu. I tak, powinieneś używać HTTPS, jeśli obawiasz się o poufność swoich danych.
Jonathon Reinhart

4
@JonathonReinhart Ale jeśli token wkrótce wygaśnie, mój klient będzie musiał zdobyć nowy token, od czasu do czasu ponownie się uwierzytelniając. Czy to nie jest nudne?
smwikipedia,

@JonathonReinhart Myślę, że rozumiem, dlaczego token jest krótkotrwały. Ponieważ w ten sposób serwer nie musi śledzić wygaśnięcia tokena, a tym samym zrobić miejsce na skalowalność. To jest coś trade-offpomiędzy having finer control of token expirationi having better scalability.
smwikipedia,

2
Czy to też może pomóc? - „Częstym mechanizmem bezpieczeństwa służącym do wykrywania kradzieży tokenów jest śledzenie pochodzenia adresu IP żądania”. - szczegółowo opisane w ostatniej sekcji tutaj - firebase.google.com/docs/auth/admin/manage-sessions
Ula

3
Teoretycznie nie można zapobiec kradzieży żetonów. Najlepsze, co możemy zrobić, to wykryć, że tak się stało, a następnie jak najszybciej odwołać sesję. Najlepszą metodą wykrywania jest użycie obrotowych tokenów odświeżania (jak sugeruje RFC 6819). Oto blog, który szczegółowo to wyjaśnia: supertokens.io/blog/…
Rishabh Poddar

Odpowiedzi:


284

Jestem autorem biblioteki węzłów, która obsługuje uwierzytelnianie na dość głębokiej ścieżce ekspresowej , więc wrzucę tu trochę informacji.

Po pierwsze, JWT zazwyczaj NIE są szyfrowane. Chociaż istnieje sposób na szyfrowanie JWT (patrz: JWE ), nie jest to bardzo powszechne w praktyce z wielu powodów.

Następnie każda forma uwierzytelnienia (przy użyciu JWT lub nie) podlega atakom MitM (man-in-the-middle). Ataki te zdarzają się, gdy osoba atakująca może ZOBACZYĆ RUCH SIECI podczas wysyłania żądań przez Internet. Oto, co widzi Twój dostawca usług internetowych, NSA itp.

Właśnie temu SSL zapobiega: poprzez szyfrowanie ruchu sieciowego w twoim komputerze -> jakiś serwer podczas uwierzytelniania, osoba trzecia, która monitoruje twój ruch sieciowy NIE może zobaczyć twoich tokenów, haseł itp., Chyba że w jakiś sposób jest w stanie aby uzyskać kopię prywatnego klucza SSL serwera (mało prawdopodobne). To jest powód, dla którego SSL jest OBOWIĄZKOWY dla wszystkich form uwierzytelnienia.

Powiedzmy jednak, że ktoś może wykorzystać Twój SSL i może wyświetlić Twój token: odpowiedź na twoje pytanie brzmi: TAK , osoba atakująca będzie mogła użyć tego tokena do podszywania się pod Ciebie i wysyłania żądań do Twojego serwera.

Teraz tu przychodzą protokoły.

JWT są tylko jednym standardem dla tokena uwierzytelniającego. Mogą być używane do prawie wszystkiego. Powodem, dla którego JWT są fajne, jest to, że możesz osadzić w nich dodatkowe informacje i sprawdzić, czy nikt się z nimi nie pomylił (podpisywanie).

JEDNASTY JWT nie mają jednak nic wspólnego z „bezpieczeństwem”. Pod każdym względem JWT są mniej więcej tym samym kluczem API: po prostu losowymi ciągami, których używasz do uwierzytelnienia na jakimś serwerze.

Co sprawia, że ​​twoje pytanie jest bardziej interesujące, to używany protokół (najprawdopodobniej OAuth2).

OAuth2 działa w ten sposób, że został zaprojektowany, aby dać klientom TYMCZASOWE tokeny (takie jak JWT!) Do uwierzytelnienia TYLKO KRÓTKIM OKRESIE!

Chodzi o to, że jeśli twój token zostanie skradziony, atakujący może go użyć tylko przez krótki czas.

Dzięki OAuth2 musisz co jakiś czas ponownie uwierzytelniać się na serwerze, podając swoją nazwę użytkownika / hasło LUB poświadczenia API, a następnie odzyskując token w zamian.

Ponieważ ten proces zdarza się od czasu do czasu, twoje tokeny często się zmieniają, co utrudnia atakującym ciągłe podszywanie się pod ciebie bez kłopotów.

Mam nadzieję, że to pomaga ^ ^


3
Autor następującego artykułu twierdzi, że wadą JWT jest to, że jedynym sposobem na odzyskanie skradzionego JWT jest wygenerowanie nowej pary kluczy i skuteczne wylogowanie wszystkich użytkowników. Natomiast z identyfikatorami sesji przechowywanymi w bazie danych witryna może usunąć tylko sesje użytkownika, którego dotyczy problem, i wylogować go ze wszystkich urządzeń. Nie jestem pewien, jak OAuth2 pasuje na zdjęciu tutaj, czy też pomaga złagodzić przedstawione wady. medium.com/@rahulgolwalkar/…
Marcel

4
Autor jest niepoprawny. Istnieją różne wzorce projektowe, których można użyć do unieważnienia tokenów. Ale ogólnie: użycie JWT do dowolnego celu uwierzytelnienia jest złym pomysłem. O wiele bardziej efektywne jest użycie ciasteczka sesyjnego z osadzonym wewnątrz pomysłem sesji podpisanym kryptograficznie.
rdegges 18.01.18

1
@rdegges, proszę powiedz mi, w jaki sposób JWT jest złym pomysłem na uwierzytelnianie? i jak mogę użyć sesyjnego pliku cookie, o którym wspomniałeś w swoim komentarzu powyżej?
noman tufail

6
To zbyt długo, aby wpisać jedną odpowiedź. Jeśli chcesz dowiedzieć się więcej, przedstawiłem szczegółową rozmowę na ten temat. Możesz sprawdzić moje slajdy online: speakerdeck.com/rdegges/jwts-suck-and-are-stupid
rdegges

2
Teoretycznie nie można zapobiec kradzieży żetonów. Najlepsze, co możemy zrobić, to wykryć, że tak się stało, a następnie jak najszybciej odwołać sesję. Najlepszą metodą wykrywania jest użycie obrotowych tokenów odświeżania (jak sugeruje RFC 6819). Oto blog, który szczegółowo to wyjaśnia: supertokens.io/blog/…
Rishabh Poddar

31

Wiem, że to stare pytanie, ale myślę, że mogę tu upuścić 0,50 USD, prawdopodobnie ktoś może poprawić lub przedstawić argument, aby całkowicie odrzucić moje podejście. Korzystam z JWT w RESTful API przez HTTPS (ofc).

Aby to zadziałało, zawsze powinieneś wydawać krótkotrwałe tokeny (zależnie od większości przypadków, w mojej aplikacji ustawiam exproszczenie na 30 minut i ttl3 dni, więc możesz odświeżyć ten token, dopóki ttljest on nadal aktywny ważny, a token nie został umieszczony na czarnej liście )

W authentication servicecelu unieważnienia tokenów lubię używać pamięci podręcznej warstwy ( w moim przypadku redis ) jako JWT blacklist/ ban-listz przodu, w zależności od niektórych kryteriów: (Wiem, że to łamie filozofię RESTful, ale przechowywane dokumenty są naprawdę krótkotrwały, ponieważ umieszczam na czarnej liście pozostały czas do życia - ttltwierdzą-)

Uwaga: tokenów z czarnej listy nie można automatycznie odświeżać

  • Jeśli user.passwordlub user.emailzostał zaktualizowany (wymaga potwierdzenia hasła), usługa uwierzytelniania zwraca odświeżony token i unieważnia (czarną listę) poprzednie (a), więc jeśli klient wykryje, że tożsamość użytkownika została w jakiś sposób naruszona, możesz poprosić go o zmianę hasła . Jeśli nie chcesz do tego używać czarnej listy, możesz (ale nie zachęcam cię) do zweryfikowania iat(wystawionego w) roszczenia względem user.updated_atpola (jeśli jwt.iat < user.updated_atwtedy JWT nie jest ważne).
  • Użytkownik celowo się wylogował.

Na koniec weryfikujesz token normalnie, tak jak wszyscy.

Uwaga 2: zamiast używać samego tokena (który jest naprawdę długi) jako klucza pamięci podręcznej, sugeruję wygenerowanie i użycie tokena UUID dla jtioświadczenia. Co jest dobre i myślę (nie jestem pewien, ponieważ właśnie przyszło mi to do głowy), możesz również użyć tego samego UUID, co token CSRF, zwracając z nim plik secure/ non-http-onlycookie i poprawnie implementując X-XSRF-TOKENnagłówek za pomocą js. W ten sposób unikasz pracy obliczeniowej polegającej na tworzeniu kolejnego tokena do kontroli CSRF.


9
Nigdy nie jest za późno, aby przekazać swój pomysł. Dzięki za odpowiedź.
smwikipedia

2
Jeśli przechowujesz na serwerze czarną listę, którą należy sprawdzić przy każdym żądaniu, dlaczego po prostu nie użyć zwykłej starej sesji?
Franklin Yu

@FranklinYu Czarna lista jest o wiele tańsza niż pełny sklep z sesjami. Ponieważ przechowujesz krótkotrwałe obiekty klucz-wartość (w zależności od pozostałego czasu życia, który powinien być dość krótki), i dzieje się tak tylko w przypadku akcji wylogowania i takich, które unieważniają tokeny, więc nie każdy token jest przechowywane
Frondor,

2
Jak tanie może być? Po pierwsze, jeśli nadal przechowujesz coś po stronie serwera, nie cieszysz się korzyścią „skalowalności”, o którą twierdzi JWT, ponieważ nadal istnieje centralny serwer czarnej listy, z którym cały serwer aplikacji musi porozmawiać, zanim cokolwiek zrobi. Jeśli musisz przechowywać tylko 1k czarnej listy z powodu szybkiego wygaśnięcia, możesz zrobić to samo dla sesji, a zatem musisz przechowywać tylko sesje 1k.
Franklin Yu,

3
Lubię to podejście. W rzeczywistości nie musisz sprawdzać czarnej listy przy każdym żądaniu, tylko w przypadku żądania, które nastąpi po wygaśnięciu JWT (które możesz odczytać z samego tokena) i do okresu TTL później. W „standardowym” przypadku użycia powinno to nastąpić co najwyżej raz w życiu danego tokena. Po odświeżeniu prawdopodobnie możesz odrzucić wszelkie przyszłe żądania odświeżenia. Dzięki @Frondor
John Ackerman

7

Przepraszam, że się trochę spóźniłem, ale miałem podobne obawy i teraz chcę wnieść coś w to samo.

1) rdegges dodał doskonały punkt, że JWT nie ma nic wspólnego z „bezpieczeństwem” i po prostu sprawdza, czy ktoś pomieszał z ładunkiem, czy nie (podpisanie); ssl pomaga zapobiegać naruszeniom.

2) Teraz, jeśli ssl jest również w jakiś sposób zagrożony, każdy podsłuchujący może ukraść nasz token okaziciela (JWT) i podszyć się pod prawdziwego użytkownika, krok dalej, co można zrobić, aby uzyskać „dowód posiadania” JWT od klienta .

3) Teraz, dzięki takiemu podejściu, prezenter JWT posiada szczególny klucz Proof-of-Possession (POP), który odbiorca może kryptograficznie potwierdzić, czy żądanie pochodzi od tego samego autentycznego użytkownika, czy nie.

I mowa Dowód posiadaniu artykule dla tego i jestem przekonany ze apporach.

Będę zachwycony, jeśli będę mógł coś wnieść.

Pozdrawiam (y)


0

Czy nie możemy po prostu dodać adresu IP początkowego hosta, który zażądał wygenerowania tego tokenu JWT w ramach roszczenia? Teraz, gdy JWT zostanie skradziony i użyty z innego komputera, gdy serwer zweryfikuje ten token, możemy zweryfikować, czy żądany adres IP komputera jest zgodny z tym ustawionym jako część roszczenia. To się nie zgadza i dlatego token można odrzucić. Również jeśli użytkownik spróbuje zmanipulować token, ustawiając swój własny ip na token, token zostanie odrzucony, gdy token zostanie zmieniony.


Jest to jedno z możliwych rozwiązań, ale dla klientów za firewallem typowe jest, aby adres IP był wybierany z puli adresów i który można zmienić w dowolnym momencie.
SpeedOfSpin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.