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,SecureirSameSite.
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ūsena | Stateful (saugoma serveryje) | Stateless (nešama kliento) |
| Saugojimas serveryje | Būtinas (Redis, duomenų bazė) | Joks |
| Atšaukimas | Momentinis | Sunkus iki galiojimo pabaigos |
| Horizontalus plečiamumas | Reikalinga bendra saugykla | Natūralus |
| Perduodamas dydis | Mažas (vienas identifikatorius) | Didesnis (pasirašyti claim'ai) |
| Tarp domenų / SSO | Varžantis | Tinkamas |
| XSS paviršius | Mažas, jei slapukas HttpOnly | Didelis, jei saugoma localStorage |
Saugumas: XSS, CSRF ir atšaukimas
Abu metodai yra saugūs, jei tinkamai įgyvendinti, bet jų rizikos skiriasi.
- XSS:
HttpOnlysesijos slapukas yra neprieinamas JavaScript, todėl apsaugotas nuo vagystės per injekciją. JWT, saugomaslocalStorage, priešingai, perskaitomas bet kurio skripto, todėl tampa pageidaujamu taikiniu. JWT saugojimasHttpOnlyslapuke 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ų (
SameSiteatributas, anti-CSRF žetonas). JWT, rankiniu būdu siunčiamasAuthorizationantraš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.