JWT, a bezpieczeństwo i trzymanie sesji

0

Bawię się ostatnio różnymi sposobami uwierzytelniania i autoryzacji.
Zastanowiło mnie JWT i nurtują mnie 2 pytania:

  1. Uwierzytelniamy użytkownika, tworzymy token i potem on sobie lata między frontem a api.
    Tyle, że można go bez problemu odkodować. Innymi słowy, jeśli przechwycę czyjś request, wezmę z niego token (jwt) i dodam do swoich requestów to mam pełny dostęp.
    Czy ja źle rozumiem? Bo jeśli dobrze to to jest raczej mało bezpieczne.

  2. Gdzie przechowywać najlepiej sesję. Choćby po to by mieć zapisane kiedy jaki użytkownik się logował albo ile mamy otwartych właśnie sesji (zalogowanych użytkowników)?

2

AD 1. Tak odkodujesz, dlatego lepiej nie trzymać w nim wrażliwych danych takich jak hasła, pesele. JWT składa się z trzech części oddzielonych kropkami i za pomocą ostatniej z nich (signature) serwer może zweryfikować, czy token został wystawiony przez niego, czy został spreparowany. W tokenie najlepiej trzymać e-mail lub identyfikator użytkownika i jakieś wrażliwe dane pobierać z bazy na podstawie tego id.
Co do przechwycenia tokenu, to tak - istnieje taka możliwość dlatego lepiej używać szyfrowania SSL.

AD 2. JWT jest bezstanowy i wystawia się go na pewien czas (na przykład jedną godzinę). Dlatego nie masz informacji, czy dany użytkownik 55 minut po zalogowaniu nadal jest aktywny na stronie. Rozwiązanie jakie widzę to jakiś mechanizm zakładający, że jeśli użytkownik nie użył swojego tokenu przez pewien czas (np. 5 minut) to uznajemy go za nieaktywnego. Choć to mój pomysł na szybko - może ktoś ma coś lepszego.

1

Nie czytałem. Pierwsze lepsze co mi w Google wyskoczyło. Sekuraki konkretnie podchodzą do spraw bezpieczeństwa, więc wierze, że wszystko jest dobrze opisane.
bezpieczeństwa JWT (JSON Web Token) - Sekurak

2
  1. A czym to się różni od sesji i ciastek? Też jeśli przechwycisz request użytkownika, to odczytasz SESSIONID (zależnie od języka/frameworka) i możesz spreparować request po swojej stronie. Także jeśli to jest "niebezpieczne" no to wszytko jest niebezpieczne :) Dlatego HTTPS itp.

  2. Tak jak wspomniano, JWT jest bezstanowy. Nie ma sesji, serwer totalnie "nie wie" o tym, że jakiś użytkownik "jest zalogowany" bo pojęcie "zalogowania" nie istnieje - w sensie wiadomo, robi się ściemę na froncie że user jest zalogowany, ale tak technicznie wszystko jest bezstanowe, co najwyżej front wie że token jest ważny. Więc - jeśli chcesz mieć info kiedy się logował, no to zapisujesz to do bazy i tyle. Ile mamy otwartych sesji - nie ma sesji of kors :) więc można np. śledzić zapytania i patrzeć, kiedy poszedł ostatni request od danego użytkownika.

0

Ok, rozumiem. To, że bezstanowy to jasne.
Ale mnie chodzi bardziej o taki scenariusz:

  1. mam konto na stronie. Loginem jest mój email i mam ustawione hasło.
  2. znam kogoś kto też ma takie konto. Załóżmy, że nawet uprawnienia nam się zgadzają. Znam jego adres email. Nie znam hasła.
  3. Loguję się swoim emailem i hasłem. Serwer generuje JWT. Przesyła na front, który zapisuje to JWT, dajmy na w localStorage.
  4. Widzę to JWT w przeglądarce (developer tools). Biorę go, rozkodowuję, podmieniam swój email tam zapisany na email znajomego. Zakodowuję. Podmieniam wartość w localStorage.
  5. Strzelam do serwera. Jestem zalogowany jako znajomy.

Chyba to zbyt proste i ja po prostu czegoś nie kumam z tym JWT.
Chodzi mi o to, ze skoro da się to rozkodować bez najmniejszego problemu, widać to w przeglądarce jak ciastko, to równie dobrze mogłoby to być plaintextem przesyłane.

2

Punkt 4 jest fałszywy. JWT są podpisywane na serwerze, więc po zmodyfikowaniu podpis nie będzie się zgadzał.

0

Czy w takim razie jesli:
a) nie chcę używać IdentityServer, bo
- nie planuję mieć osobnego serwisu do autentykacji\autoryzacji,
- nie będę nigdy uwierzytelniał się przez zewnętrzne serwisy.

b) chcę zrobić logowanie na najprostszych obiektach User i Role, to czy używanie do tego celu ciasta (cookie) jest bezpieczne?

Jeśli tak, to gdzie lepiej trzymać claimsy?
W ciastku (secure) czy w JWT?

2
hercules napisał(a):

a) nie chcę używać IdentityServer, bo
- nie planuję mieć osobnego serwisu do autentykacji\autoryzacji,
- nie będę nigdy uwierzytelniał się przez zewnętrzne serwisy.

Nie chcesz używać to twój wybór jednak oba argumenty które podajesz mijają się z prawdą. Nie potrzebujesz mieć osobnego serwisu na autoryzję by użyć identity, jest to zalecana praktyka ale Identity do tego nie zmusza. A to ,że nie będziesz się uwierzytelniał przez zewnętrzne serwisy a ktoś ci każe? W identity dane trzymasz u siebie w bazie a kod jest opensource więc masz w niego wgląd. Dlatego te argumenty nie mają kompletnie żadnego sensu. A próba tworzenia serwisu uwierzytelniania samemu skończy się problemami, bo z tego co piszesz wnioskuje ,że nie masz zbyt dużej wiedzy w zabezpieczaniu aplikacji webowych dlatego moim zdaniem Identity to narzędzie ,które warto poznać. Ale zrobisz jak będziesz uważał za słuszne.

1

JWT składa się z 3 elementów:

  • header - informacja o typie funkcji haszującej jednokierunkowej jaka została użyta do wygenerowania sygnatury (jawna),
  • payload - dane użytkownika, dowolne jakie wrzuca do tokenu (jawne).

I teraz najważniejsze w tym wszystkim:

  • signature - ciąg znaków odpowiadający za to autentyczność tokenu. Dzięki niemu serwer ma pewność, że dane w payload nie zostały zmienione przez kogokolwiek. Wygenerowany za pomocą funkcji haszującej jednokierunkowej. Jest on stworzony w taki sposób (w uproszczeniu, bo dane są w base64 i oddzielone kropkami, ale to szczegół):
funkcja_haszująca(header + payload + HASŁO)

Co sprawia, że ten sposób zapewnia autentyczność tokenu? Jest to HASŁO, które zna tylko serwer. Po zmianie choćby jednego znaku w payload zmienia się cała sygnatura. Wadliwa sygnatura = token został spreparowany = serwer odrzuca token.
Po zmianie adresu email w payload nie wiesz jak wygenerować signature. Dlaczego? Bo nie znasz HASŁA.

1

Dodam od siebie dwa grosze co to tej bezstanowości JWT. Z technicznego punktu widzenia jest to oczywiście prawdą, natomiast jeśli chodzi o implementację to czasem się nie obejdzie od trzymania sesji po stronie serwera, chociażby po to żeby faktycznie wspierać opcję wylogowania się po stronie serwera, a nie tylko wyrzucać JWT po stronie klienta i stwarzać pozory tego że użytkownik się wylogował podczas kiedy requesty z tokenem nadal byłyby akceptowane.

Jako że tokena JWT z racji jego natury nie można unieważnić, takie unieważnianie trzeba zaimplementować samemu (lub skorzystać z gotowych rozwiązań). Wtedy trzymamy informację o sesji powiązanej z tokenem, a kiedy użytkownik się wyloguje wywalamy tokena z sesji. Wtedy pomimo tego że technicznie token nadal będzie ważny, to serwer i tak będzie odrzucał requesty ponieważ nie znajdzie takiego tokena w sesji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1