JWT vs sesija: kurį autentifikavimo mechanizmą pasirinkti?

Autentifikuoti vartotoją reiškia kiekvienos užklausos metu žinoti, kas jis yra. Konkuruoja dvi didelės šeimos: serverio sesijos, kur serveris seka prisijungusį vartotoją, ir JSON Web Token (JWT), kur tapatybė keliauja kliento nešamame pasirašytame žetone. Pasirinkimas turi įtakos saugumui, gebėjimui plėstis ir vartotojo atjungimo paprastumui. Štai kaip nuspręsti pagal jūsų kontekstą.

Serverio sesijos (stateful)

Naudojant sesiją, serveris prisijungimo metu sukuria sesijos identifikatorių, saugo susijusius duomenis (tapatybę, vaidmenis, krepšelį) serverio pusėje (atmintyje, Redis, duomenų bazėje) ir grąžina naršyklei slapuką, kuriame yra tik šis identifikatorius. Kiekvienos užklausos metu serveris perskaito slapuką, suranda sesiją ir žino, kas kalba.

  • Būsena serverio pusėje: tiesos šaltinis lieka serveryje, klientas neša tik nepermatomą nuorodą.
  • Momentinis atšaukimas: sesijos pašalinimas serverio pusėje akimirksniu atjungia vartotoją.
  • Slapukas: naršyklės perduodamas automatiškai, geriausia su HttpOnly, Secure ir SameSite.

JSON Web Token (stateless)

JWT yra savarankiškas žetonas, sudarytas iš trijų base64url užkoduotų dalių, atskirtų taškais: antraštės, naudingosios apkrovos (claim'ų, pavyzdžiui vartotojo identifikatoriaus ir galiojimo pabaigos) ir parašo. Serveris pasirašo žetoną prisijungimo metu; vėliau jam pakanka patikrinti parašą, kad pasitikėtų turiniu, nieko nesaugodamas.

  • Be būsenos: visa reikalinga informacija yra žetone, serveriui nereikia bendros atminties.
  • Tikrinamas visur: bet kuri paslauga, žinanti raktą, gali patvirtinti žetoną, patogu paskirstytoms architektūroms ir SSO.
  • Įrankiai: žetoną galite patikrinti su mūsų JWT dekoderiu, jo parašą patvirtinti su JWT tikrintuvu arba sukurti naują su JWT generatoriumi.

Palyginimo lentelė

Kriterijus Serverio sesija JWT
BūsenaStateful (saugoma serveryje)Stateless (nešama kliento)
Saugojimas serveryjeBūtinas (Redis, duomenų bazė)Joks
AtšaukimasMomentinisSunkus iki galiojimo pabaigos
Horizontalus plečiamumasReikalinga bendra saugyklaNatūralus
Perduodamas dydisMažas (vienas identifikatorius)Didesnis (pasirašyti claim'ai)
Tarp domenų / SSOVaržantisTinkamas
XSS paviršiusMažas, jei slapukas HttpOnlyDidelis, jei saugoma localStorage

Saugumas: XSS, CSRF ir atšaukimas

Abu metodai yra saugūs, jei tinkamai įgyvendinti, bet jų rizikos skiriasi.

  • XSS: HttpOnly sesijos slapukas yra neprieinamas JavaScript, todėl apsaugotas nuo vagystės per injekciją. JWT, saugomas localStorage, priešingai, perskaitomas bet kurio skripto, todėl tampa pageidaujamu taikiniu. JWT saugojimas HttpOnly slapuke panaikina šį JWT pranašumą, bet vėl įveda CSRF riziką.
  • CSRF: slapukai siunčiami automatiškai, todėl be apsaugos pažeidžiami CSRF atakų (SameSite atributas, anti-CSRF žetonas). JWT, rankiniu būdu siunčiamas Authorization antraštėje, nėra paveiktas.
  • Atšaukimas: tai silpnoji JWT vieta. Kadangi jis savarankiškas, jo negalima paskelbti negaliojančiu iki galiojimo pabaigos, neįvedant serverio būsenos (atšaukimo sąrašo, juodojo sąrašo). Sesija pašalinama akimirksniu.

Plečiamumas ir architektūra

Viename serveryje sesijos yra paprastos. Kai tik paskirstote apkrovą keliems egzemplioriams, kiekvienas egzempliorius turi pasiekti sesijas: reikia bendros saugyklos (Redis) arba sticky sesijų. JWT čia spindi, nes bet kuris egzempliorius patvirtina žetoną be tinklo užklausų ir bendros saugyklos.

  • Mikroservisai: JWT perduoda tapatybę iš vienos paslaugos į kitą be centrinės duomenų bazės.
  • Viešos API ir mobilieji: JWT išvengia slapukų valdymo natyvaus kliento pusėje.
  • Klasikinis monolitas: sesija lieka paprastesnė ir saugesnė pagal numatymą.

Kada rinktis vieną ar kitą

Rinktis sesijas, kai

  • Kuriate klasikinę žiniatinklio programą su serverio pusės atvaizdavimu
  • Momentinis atšaukimas yra kritiškai svarbus (bankas, sveikata, back-office)
  • Norite saugiausio sprendimo pagal numatymą, su mažiausiai spąstų
  • Jūsų infrastruktūra be vargo išlaiko bendrą sesijų saugyklą

Rinktis JWT, kai

  • Teikiate API, naudojamą SPA, mobiliųjų ar trečiųjų šalių
  • Turite mikroservisų architektūrą arba SSO tarp domenų
  • Turite plėstis horizontaliai be bendros saugyklos
  • Sutinkate valdyti trumpą galiojimą ir žetonų atnaujinimą

Rekomendacija

Daugumai žiniatinklio programų serverio sesijos lieka saugiausias ir paprasčiausias pasirinkimas: momentinis atšaukimas, HttpOnly slapukas ir jokio žetonų valdymo kliento pusėje. Palikite JWT tiems atvejams, kai jo bebūsenė prigimtis teikia tikrą vertę: stateless API, mobilieji, mikroservisai, SSO.

Jei renkatės JWT, išlaikykite trumpą galiojimo laiką (kelias minutes) kartu su atnaujinimo žetonu (refresh token), saugomu HttpOnly slapuke, ir numatykite atšaukimo sąrašą jautriems atvejams. Taip sujungiate geriausią iš abiejų pasaulių.

Dažnai užduodami klausimai

Ar JWT yra užšifruotas?

Ne, pagal numatymą JWT yra tik pasirašytas, ne užšifruotas. Jo naudingoji apkrova užkoduota base64url ir perskaitoma bet kurio, kas ją perima. Niekada nedėkite jautrių duomenų atviru tekstu į JWT. Norėdami užšifruoti turinį, turite naudoti JWE (JSON Web Encryption).

Kur saugoti JWT kliento pusėje?

Saugiausia yra HttpOnly, Secure ir SameSite slapukas, kuris apsaugo nuo vagystės per XSS. localStorage yra paprastesnis, bet atskleidžia žetoną bet kuriam kenkėjiškam skriptui. Venkite jo aukšto privilegijų lygio žetonams.

Kaip atjungti vartotoją naudojant JWT?

Kadangi žetonas yra savarankiškas, tikras atjungimas reikalauja arba laukti jo galiojimo pabaigos, arba palaikyti atšaukimo sąrašą serverio pusėje. Todėl naudojamas trumpas galiojimo laikas ir atnaujinimo žetonas, kurį galima atšaukti.

Ar galima derinti sesijas ir JWT?

Taip, tai įprasta praktika: trumpo galiojimo JWT prieigos žetonas API iškvietimams ir atnaujinimo žetonas, valdomas kaip sesija (saugomas ir atšaukiamas serverio pusėje) prieigos žetonui atnaujinti.