Autentificare SPA - Best practices

O întrebare din curiozitatea de a afla care este cea mai buna sau folosită metoda pentru rezolvarea următoarei probleme.

Voi cum faceți logica unei autentificări intr-o aplicație web de tipul SPA? Și aici mă refer la o descriere mai indetaliata și nu doar la enumerarea a principiilor.

Update:

Eu procedez in felul urmator:

La fel folosec JWT, iar cand se autentifica cu credentialele se genereaza un token. Ca un plus de securitate token-ul nu il trimit la interfata si il setez din backend in cookie-urile browser-ului cu proprietatea httpOnly, astfel sa nu poata fi accesat de pe front-end. Ca un plus folosesc si proprietatile secured si signed
Inainte sa se deschida aplicatia, ca sa verific daca un utilizator este logat, fac un request la o ruta anume in back-end care citeste acest cookie si returneaza user-ul aferent care este dupa salvat in memoria aplicatiei. Rutele sunt protejate si pe back-end ( folosind cookie-ul) si pe front-end (folosind user-ul salvat in memoria aplicatiei).

2 Likes

Personal folosesc JWT. API-ul genereaza un token folosind credentialele utilizatorului iar frontend-ul salveaza acest token si il foloseste la fiecare request catre API. Token-ul este inclus in header Authorization: Bearer <token>.

In backend este un middleware care verifica acest token pentru fiecare request. Daca token-ul este valid, se merge mai departe cu procesarea request-ului. In caz contrar, un mesaj de eroare este intors (401 Unauthorized).

In payload-ul token-ului includ doar id-ul utilizatorului.

4 Likes

Tot JWT, insa folosesc Auth0 care ofera biblioteci atat pentru backend cat si pentru frontend, plus ca ofera deja API-uri pentru partea de user management si o multime de alte integrari cu Social, SSO, etc.

Deci salvezi token-ul in state-ul aplicatiei si il trimiti la fiecare request ca si header. Cum faci ca logarea sa fie una persistenta atunci?

Nu am inteles la ce te referi prin logare persistenta. Token-ul are o validitate de 24 de ore. Cat timp frontend-ul are acces la token si nu a expirat, utilizatorul ramane logat. Daca token-ul este sters din local storage sau a expirat, utilizatorul este redirectionat la pagina de login pentru a genera un nou token.

LE: am inteles la ce te referi. Token-ul este salvat in local storage, nu in state-ul aplicatiei.

daca folosesti SSR - atunci cookie, altfel localstorage e ok

Varianta buna este cea propusa de Alexandru_Bugarin, cu header HTTP. Folosirea Cookie se bazeaza pe browser, pe viitor s-ar putea sa servesti si alt tip de clienti.

1 Like

La cum ai descris faci un mix intre Session based auth (cookie) si Token based auth. Este ori una ori alta, daca vrei sa fie “best practice”:

Cand faci referire la JWT este mai mult decat partea de Token, aici ai un exemplu.

3 Likes

Cred ca foloseste cookie-urile doar ca metoda de stocare a unui JWT.
Nu cred ca e Session based auth doar pentru ca pastrezi ceva intr-un cookie.
Ca sa nu mai pui HTTP request interceptors la care sa adaugi un header pt JWT, il poti salva in cookie si se va atasa automat la request (atata timp cat requesturile se fac la serverul care a emis cookie-ul)

https://github.com/ory/kratos pare o solutie super faina pentru backend.

Logica mea: Fiecare limbaj are best practices undeva pe github sau pe owasp, o caut, de exemplu Java JWT owasp best practices/awesome si vad ce librarii exista, daca exista o librarie o sa o folosesc. Cum eu sunt mai mult pe frontend (si integral aplicatii care n-au nimic deaface cu SSR), login-ul il salvez in localstorage sau in sesiunea user-ului (de exemplu pe Google AppsScript iti setezi token-ul pe sesiunea user-ului, care e un API in Google Sheets, GMail etc.)

Daca login-ul este salvat in localstorage, atunci nu orice cod care ruleaza in aplicatie are access la credentialele tuturor user-ilor?

Are access la sesiunea user-ului pe domeniul pe care rulezi aplicatia. (degeaba iei token-ul ca nu o sa te autentifice pe alt domeniu si la localstorage ai acces iarasi doar in domeniul in care l-ai setat) Daca vrei sa rulezi cod nesigur trebuie sa il pui intr-un iframe care ruleaza pe alt domeniu.

Ok si atunci, daca deshid local storage, copiez acel token si il pun in alt browser (pe aceeasi sau pe alta masina) atunci am access la contul user-ului ?

Da, daca copiezi manual teoretic da (poate fi legat si de userAgent totusi). (dar automat nu e posibil din cate stiu, mult succes sa iei localstorage-ul din memorie in chrome)

Ideea e daca un script sau o dependenta folosita este hack-uita sau cineva gaseste un mod de a face XSS atunci cu un simplu window.localStorage poate face rost de token-uri in mod automat.

Aici intervin testele automate, testele manuale si newsletter-urile pe librariile pe care le folosesti. (de obicei un npm audit e destul la build) :smiley: XSS-ul se poate testa automat pe fiecare input in care poate introduce cineva ceva.

Nu degeaba te plateste cineva sa ii faci o aplicatie. Alternative nu prea exista. (maybe cache api/IndxedDB dar e the same stuff, te ajuta doar daca ai nevoie de web workers) Sunt multe cazuri in care un cookie nu e o optiune. (nu poti seta stare pe server fiindca nu stii pe care server nimeresti si dupa ai de rezolvat problema cu sincronizarea intre mai multe locatii in load balancer)
Intr-o corporatie cu legacy stuff load balancer-ul poate primeste update-uri o data sau de doua ori pe an, poate nu vrei sa te complici cu toata birocratia necesara sa introduci un cookie sincronizat pentru tine.

Fun stuff:


Se numeste Replay Attack, deaceea se foloseste Refresh Token, iar pe Session based auth se face sign si refresh la cookie la fiecare request sau dupa un timeout.

3 Likes

În cazul în care ai o vulnerabilitate XSS, probleme sunt şi dacă foloseşti localStorage şi dacă foloseşti cookie-uri. Scopul unui atacator este să trimită request-uri maliţioase către API, ceea ce poate face citind token-ul din localStorage şi construind request-urile altundeva SAU construind aceste request-uri direct în codul injectat, request-uri la care browser-ul tău va ataşa cookie-ul, fără ca atacatorul să aibe nevoie de access la el.

O altă posibilă vulnerabilitate dacă foloseşti cookie-uri pe API e CSRF: request-uri maliţioase construite în afara aplicaţiei (eg: accesând un link fake) şi trimise către API, la care browser-ul ataşează automat cookie-ul. Într-o aplicaţie web tradiţională, asta se mitiga prin generarea unui token la afişarea unei pagini / formular şi stocarea lui pe sesiune, care era apoi verificat pe server la submit. Ca să mai previi din riscul ăsta, ar mai trebui să ai un header custom, gen X-API-Token pe care să îl verifici pe toate call-urile către API.

Vezi si https://auth0.com/docs/security/common-threats

3 Likes