JWT - idea Refresh Token i jego sens

2

Cześć,
chciałem się zapytać jaka jest faktyczna idea refresh tokenu w JWT i OAuth 2.0? W jakim dokładnie celu się go stosuje? Niektórzy piszą, że to kwestia bezpieczeństwa - na wypadek, gdyby token dostępu został wykradziony, ale ten argument chyba jest słaby, bo refresh token również można wykraść.
Bardziej sensowny jest argument, że refresh token można unieważnić / zmienić uprawnienia etc, ale czy jest w ogóle potrzeba jego stosowania?

Moje wątpliwości wynikają z poniższych wniosków:
Jeśli dobrze rozumiem, zasada działania wygląda to tak:
logujemy się na stronie -> otrzymujemy token dostępu, który ma krótki czas życia, oraz refresh token, który ma bardzo długi czas życia -> jak upłynie określony czas token dostępu wygasa i trzeba go odnowić za pomocą refresh tokenu. Wysyłamy więc refresh token do serwera, który go weryfikuje np. czy nie został anulowany, a jeśli nie to otrzymujemy nowy token dostępu.

Ale czy nie wygodniej zrobić to tak:
logujemy się na stronie -> otrzymujemy token dostępu, który ma krótki czas życia -> po stronie serwera zapisujemy czy token użytkownika może być przedłużany ewentualnie do kiedy, jakie ma uprawnienia etc. -> gdy token dostępu wygasa to po stronie serwera sprawdzamy czy możemy go odnowić a jeśli tak to przesyłamy nowy token dostępu z aktualnymi dostępami.

W obu przypadkach, gdy token dostępu wygasa musimy zweryfikować czy możemy wygenerować nowy token a jeśli tak to z jakimi uprawnieniami. Różnica jest tylko taka, że moje rozwiązanie pomija stosowania refresh tokenu.

Będę bardzo wdzięczny za informację czy moje rozumowanie jest właściwe, a jeśli nie to gdzie popełniam błąd, ewentualnie jakie inne korzyści wynikają z refresh tokenu?
Z góry dziękuję za pomoc.

4

Działa to tak jak napisałes. Czy poprawia bezpieczeństwo? Na pewno tak w porównaniu do generowania JWT (access tokenu) z dlugim czasem ważności - typu 30 dni. Poza tym refresh token jest wysyłany do authorization serwera, a access token bezpośrednio do resource serwera.
Głównymi idealmi tego rozwiązania jest właśnie bezpieczeństwo, ale też wygoda i performance. Użytkownik nie musi się logować ponownie po godzinie czy dwóch godzinach. Jeśli chodzi o performance - dodatkowym plusem jest to że JWT (access token) nie musisz trzymać/pobierać z jakiegoś trwałego storage. Możesz sobie go trzymać w pamięci aplikacji (dostęp będzie bardzo szybki), a jak aplikacja się wywali - wygeneruje nowy JWT z refresh tokenu (który moze być w trwałym storage). Jest to również zaletą przy skalowalności.

Ale czy nie wygodniej zrobić to tak:
logujemy się na stronie -> otrzymujemy token dostępu, który ma krótki czas życia -> po stronie serwera zapisujemy czy token użytkownika może być przedłużany ewentualnie do kiedy, jakie ma uprawnienia etc. -> gdy token dostępu wygasa to po stronie serwera sprawdzamy czy możemy go odnowić a jeśli tak to przesyłamy nowy token dostępu z aktualnymi dostępami.

Wygodniej raczej nie, bo musiał byś pisać nowe funkcjonalności które są już zapewnione w wielu rozwiązaniach oauthowych. Dodatkowo przy takim roziązaniu użytkownik musiałby wysyłac cały czas requesty (bo jak upewnisz się po stronie serwera że token wygasa). Np wygenerujesz token o wazności 60min. Użytkownik zrobi kolejny request po 2h. Co wtedy? Wylogowany?
No i jeszcze jeden problem - przy każdym requeście użytkownik (aplikacja kliencka) musiałby sprawdzać czy przypadkiem serwer nie podmienił tokenu w response. Wysyłasz jakiegoś prostego GET-a, ale musisz przy okazji sprawdzić czy token nie został podmieniony na nowy.

2

OAuth 2.0 generalnie ma troche inne zadanie. Jest to udostępnianie możliwości uwierzytelniania zewnętrznemu serwisowi.
Co do samego bezpieczeństwa JWT: jeśli token ci wycieknie to żadne expiration time nie pomoże. Dlatego tak ważne jest zabezpieczanie połączenia np poprzez implementację certyfikatu SSL

3
Korges napisał(a):

Co do samego bezpieczeństwa JWT: jeśli token ci wycieknie to żadne expiration time nie pomoże. Dlatego tak ważne jest zabezpieczanie połączenia np poprzez implementację certyfikatu SSL

To jeszcze nie wszystko, bo nadal część ruchu może być niezabezpieczona. Chyba, że wymusisz to przez HSTS. Ale nadal możesz się wrypać w MiTM albo inny spoofing i "niechcący" token zostanie wysłany na lewy serwer, który też się przecież przedstawi swoim certyfikatem - więc żeby mieć absolutną pewność powinieneś najpierw znać certyfikat danego serwera i mu ufać.

No i zawsze można znaleźć sposób np. na wykradzenie tokenu po stronie przeglądarki przez XSS i tutaj SSL nie uratuje :]

Teoretycznie "trochę" da się poprawić sytuację rotując (również refresh) tokeny i unieważniając stare po użyciu: https://auth0.com/docs/tokens[...]tokens/refresh-token-rotation - przynajmniej o tyle, że przy odrobinie szczęścia jednorazowy token zostanie już użyty do czegoś przez uprawnionego użytkownika, nim złodziej zdąży sam go wykorzystać.

2

To jest bardziej o sesjach, nie o OAuth 2.0, ale wnioski podobne.

2

Dziękuję wszystkim za udział w dyskusji.
Po dłuższym zastanowieniu zacząłem dostrzegać pewne dość istotne wady swojego rozwiązania, dlatego temat uważam za rozwiązany :).

1

Odświeżę, bo właśnie dziś naszedł mnie ten sam dylemat. Średnio widzę tu poprawę bezpieczeństwa, przecież oba tokeny access jaki i refresh muszą być trzymane po stronie klienta, więc jak wycieknie jeden to do drugiego też musi być dostęp. Nawet zakładając, że refresh token da mi dostęp tylko do jednego routa, a nie do wszystkich zasobów do których dostęp umożliwia access token, to i tak mogę sobie wygenerować ten access token.

1

@superdurszlak:

No i zawsze można znaleźć sposób np. na wykradzenie tokenu po stronie przeglądarki przez XSS i tutaj SSL nie uratuje

no to trzymaj go w HTTP cookie

1

Z własnego doświadczenia muszę powiedzieć że chyba (to jest całkowicie subiektywne) najlepszym rozwiązaniem jest trzymanie jakiejś sesji z tokenami. Kiedy użytkownik się wulogowuje to taki token wyrzucamy z sesji. Sesja może być przechowywana w pamięci lub w jakimś cache'u, np. Redis.

Owszem, oficjalnie JWT to brak stanu ale są inne zalety JWT z których nadal możemy korzystać jednocześnie używając sesji. Taki token nadal może być przesyłany między wewnętrznymi systemami, jak i przesyłanie potrzebnych informacji o użytkowniku w postaci claimów jest bardzo wygodne.

Oczywiście potencjalną wadą takie rozwiązania jest to że jeśli takie tokeny mają długą żywotność (dni a nawet tygodnie) to przy wykradzeniu takiego tokena mamy problem, chyba że usuniemy go z sesji. Ale to ten sam rodzaju problemu co przy wykradzeniu refresh tokena tak naprawdę.

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