javascript - Protecția CSRF cu antetul Origin CORS vs. token CSRF
Această întrebare este doar despre protejarea împotriva atacurilor Cross Site Request Forgery.
Este specific despre: Protecția prin antetul Origin (CORS) este la fel de bună ca protecția printr-un token CSRF?
Exemplu :
- Alice este conectată (folosind un cookie) cu browserul ei la
https://example.com. Presupun că folosește un browser modern. - Alice vizitează
https://evil.example, iar codul de partea clientului al evil.example efectuează un fel de cerere cătrehttps://example.com(scenariu clasic CSRF).
Deci:
- Dacă nu verificăm antetul Origin (pe server) și nu există niciun token CSRF, avem o vulnerabilitate de securitate CSRF.
- Dacă verificăm un token CSRF, suntem în siguranță (dar este puțin obositor).
- Dacă verificăm antetul Origin, cererea provenită de la codul de pe partea clientului evil.example ar trebui să fie blocată la fel cum ar fi atunci când se folosește un token CSRF - cu excepția cazului în care, într-un fel sau altul, codul evil.example ar putea să seteze antetul Origin.
Știu că acest lucru nu ar trebui să fie posibil cu XHR (vezi de exemplu Securitatea pentru Partajarea Resurselor între Origini), cel puțin nu dacă avem încredere că specificația W3C este implementată corect în toate browserele moderne (putem?)
Dar ce zici de alte tipuri de cereri - de exemplu trimiterea unui formular? Încărcarea unui script/img/... tag? Sau orice alt mod prin care o pagină poate folosi pentru a (legal) crea o cerere? Sau poate vreun hack JS cunoscut?
Notă: Nu vorbesc despre
- aplicații native,
- navigatoare manipulate,
- erori de tip cross site scripting pe pagina example.com,
- ...
Răspuns #1
știi, că acest lucru nu ar trebui să fie posibil cu XHR (vezi de exemplu Securitatea pentru partajarea resurselor între origini), cel puțin nu, dacă avem încredere că specificația W3C este implementată corect în toate browserele moderne (putem?)
La sfârșitul zilei, trebuie să „ai încredere” în browserul clientului pentru a stoca în siguranță datele utilizatorului și pentru a proteja partea client a sesiunii. Dacă nu ai încredere în browserul clientului, atunci ar trebui să încetezi să folosești web-ul pentru orice altceva decât conținut static. Chiar și folosind token-uri CSRF, ai încredere în browserul clientului să respecte corect Politica Aceleiași Origini.
Deși au existat vulnerabilități anterioare ale browserelor, cum ar fi cele din IE 5.5/6.0, unde a fost posibil ca atacatorii să ocolească Politica Aceleiași Origini și să execute atacuri, de obicei te poți aștepta ca acestea să fie remediate imediat ce sunt descoperite, iar cu majoritatea browserelor actualizându-se automat, acest risc va fi în mare parte redus.
Dar ce zici de alte tipuri de cereri - de exemplu trimiterea unui formular? Încărcarea unui script/img/... tag? Sau orice alt mod prin care o pagină poate folosi pentru a (legal) crea o cerere? Sau poate vreun hack JS cunoscut?
Antetul Origin este de obicei trimis doar pentru cererile XHR cross-domain. Solicitările de imagine nu conțin antetul.
Notă: Nu vorbesc despre
aplicații native,
navigatoare manipulate,
erori de tip cross site scripting pe pagina example.com,
Nu sunt sigur dacă acest lucru se încadrează la browsere manipulate sau nu, dar versiunile vechi de Flash permiteau setarea unor headere arbitrare, ceea ce ar fi permis unui atacator să trimită o cerere cu un header referer falsificat de pe mașina victimei pentru a executa un atac.
Răspunsul #2
Explicarea termenilor
CORS (Partajarea Resurselor între Origini) este un protocol care permite ca două domenii diferite să comunice între ele.
O cerere CORS (pre-flight) trebuie să includă atributul Origin în antet. Un răspuns al unei cereri pre-flight CORS conține atributul Access-Control-Allow-Origin în antet pentru a permite/restricționa accesul de pe un alt domeniu. Din documentația web MDN:
Atributul Origin se află în fiecare antet de cerere cu excepția cererilor GET și HEAD. O cerere CORS (pre-flight) trebuie să conțină atributul Origin, dar nu fiecare cerere cu atributul Origin este o cerere CORS (pre-flight).
Politica de aceeași origine este un mecanism pentru a restricționa comunicația între domenii.
Tokenul CSRF (Cross-Site-Request-Forgery) este stocat în sesiunea utilizatorului și trebuie trimis împreună cu o cerere POST/DELETE/PUT. Pe partea serverului, tokenul CSRF va fi comparat cu valoarea din sesiune și numai dacă coincid se va permite continuarea.
Politica aceleiași origini împiedică comunicarea între domenii
Toate browserele implementează politica de aceeași origine. Această politică evită, în general, ca o aplicație web de pe domeniul A să poată face o cerere HTTP către o aplicație de pe domeniul B. Cu toate acestea, nu restricționează toate cererile. De exemplu, politica de aceeași origine nu restricționează etichetele embed de acest tip:
<img src="https://dashboard.example.com/post-message/hello">
Este irelevant dacă răspunsul este o imagine validă — cererea este totuși executată. De aceea este important ca punctele finale care schimbă starea aplicației web să nu poată fi invocate cu metoda GET.
Protocol CORS: Verificare pre-zbor
Poți folosi CORS pentru a evita politica aceeași origine și a permite domeniului A să facă o cerere către domeniul B care altfel ar fi interzisă. Înainte ca cererea propriu-zisă să fie trimisă, va fi trimisă o cerere preliminară pentru a verifica dacă serverul permite domeniului A să trimită acest tip de cerere. Dacă da, domeniul B va avea câmpul Access-Control-Allow-Origin în antetul răspunsului și domeniul A va trimite cererea efectivă.
De exemplu, dacă nu este setat niciun Access-Control-Allow-Origin, atunci un XMLHttpRequest JavaScript ar fi restricționat pentru domeniul A printr-un preflight, fără a executa cererea pe domeniul B.
De ce ai nevoie de un token CSRF în ciuda politicii de aceeași origine
Dacă politica aceluiași origine ar funcționa pentru toate tipurile de cereri, nu ar fi nevoie să se folosească token CSRF, deoarece s-ar avea protecție completă prin politica aceluiași origine și s-ar putea folosi CORS pentru a specifica în mod explicit care domeniu poate comunica. Cu toate acestea, nu este cazul. Există câteva cereri HTTP care nu trimit o cerere prealabilă CORS!
Cereri GET, HEAD și POST cu anteturi specifice și tip de conținut specific nu trimit o cerere preliminară. Astfel de cereri sunt numite cereri simple. Aceasta înseamnă că cererea va fi executată.
Deoarece formularele există înainte de CORS și deja erau permise să trimită lucruri către orice origine, nimeni nu dorea să strice internetul existent cu cereri pre-flight pentru cererile POST. Vezi și aici:
Motivația este că elementul din HTML 4.0 (care precede XMLHttpRequest și fetch între site-uri) poate trimite cereri simple către orice origine, astfel că oricine scrie un server trebuie deja să se protejeze împotriva falsificării cererilor între site-uri (CSRF). Sub această presupunere, serverul nu trebuie să opteze în mod explicit (prin răspuns la o cerere pre-flight) pentru a primi orice cerere care arată ca o trimitere de formular, deoarece amenințarea CSRF nu este mai gravă decât cea a trimiterii de formulare. Cu toate acestea, serverul trebuie totuși să opteze explicit folosind Access-Control-Allow-Origin pentru a partaja răspunsul cu scriptul.
Din păcate, un <form action="POST"> simplu creează o cerere simplă!
Și din cauza acestor cereri simple, trebuie să protejăm rutele POST cu tokenuri CSRF (rutele GET nu au nevoie de CSRF pentru că pot fi oricum citite prin taguri încorporate, așa cum s-a arătat mai sus. Doar asigură-te că nu ai o metodă GET care să schimbe starea).
Este suficient să verifici originea cererii?
Deoarece cererea POST trimite originea în antet, iar browserul interzice modificarea ei, te-ai putea întreba dacă verificarea originii este suficientă, fără tokenul CSRF. Totuși, scripturile executate pe CLI pot seta originea la orice valoare arbitrară. De asemenea, este totuși posibil să se schimbe originea datorită unei combinații de pluginuri pe care utilizatorul le are disponibile. Un alt aspect este că browserele s-ar putea să nu o suporte (Edge a fost lansat în aprilie 2015, dar a suportat antetul origin în iunie 2015, iar în Firefox a fost un bug care a fost corectat în 2008 https://bugzilla.mozilla.org/show_bug.cgi?id=446344).
De pe Wikipedia:
Diverse alte tehnici au fost utilizate sau propuse istoric pentru prevenirea CSRF. Verificarea faptului că anteturile cererii conțin [...] antetul HTTP Origin. Cu toate acestea, aceasta este nesigură - o combinație de pluginuri de browser și redirecționări poate permite unui atacator să furnizeze anteturi HTTP personalizate într-o cerere către orice site web, permițând astfel o cerere falsificată
Astfel, se recomandă utilizarea unui token CSRF în loc să se bazeze pe antetul de origine. Dar există cazuri în care poate fi mai bine să nu existe un token CSRF din cauza expirării sesiunii.
Problemă cu token-urile CSRF
Aș evita să folosesc token-uri CSRF pentru formularele de contact. Deoarece ar putea duce la o situație în care un utilizator a scris mult timp și când trimite, sesiunea este expirată, token-ul CSRF este invalid și întregul mesaj al utilizatorului este șters. Ar fi o experiență de utilizator teribilă. Pentru un formular de contact, vrei să eviți primirea de mesaje SPAM, așa că recaptcha3 poate fi o alegere rezonabilă, deoarece nu necesită interacțiune din partea utilizatorului.
De asemenea, ați putea să măriți durata de viață a sesiunilor pe browserul dvs., dar acest lucru ar putea duce la o dimensiune mare a stocării. Alternativ, ați putea folosi sesiuni cu cookie-uri hash-uite care sunt stocate la client. Acele sesiuni nu ar trebui, de asemenea, să expire, chiar dacă clientul trebuie să facă o pauză de 12 ore înainte de a trimite formularul.
Rezumatul meu
- Folosiți token CRSF pentru punctele critice, cum ar fi autentificarea sau finalizarea comenzii în magazin
- Din motive practice, aș recomanda să nu se folosească token CSRF pentru formularele de aplicație sau formularele de contact.
- Nu avea niciodată un endpoint GET care să schimbe starea
Răspunsul #3
Conținutul web nu poate modifica antetul Origin. În plus, în conformitate cu politica aceluiași origin, un origin nu poate nici măcar să trimită antete personalizate către alte originuri. [1]
Astfel, verificarea antetului Origin este la fel de eficientă în blocarea atacurilor ca utilizarea unui token CSRF.
Principala preocupare legată de a te baza pe acest lucru este dacă permite funcționarea tuturor cererilor legitime. Cel care întreabă este conștient de această problemă și a formulat întrebarea astfel încât să excludă cazurile majore (fără browsere vechi, numai HTTPS).
Furnizorii de browsere respectă aceste reguli, dar ce se întâmplă cu pluginurile? Este posibil să nu le respecte, însă întrebarea ignoră „browserele manipulate”. Ce se întâmplă cu erorile din browser care permit unui atacator să falsifice antetul Origin? Pot exista erori care permit scurgerea tokenului CSRF între origini, așa că ar fi nevoie de mai mult efort pentru a argumenta că unul este mai bun decât celălalt.
