Che cos'è un token CSRF? Qual è la sua importanza e come funziona?


629

Sto scrivendo un'applicazione (Django, succede così) e voglio solo un'idea di cosa sia effettivamente un "token CSRF" e di come protegge i dati. I dati di post non sono sicuri se non si utilizzano i token CSRF?


13
È un token segreto specifico dell'utente in tutti i moduli e gli URL degli effetti collaterali per impedire falsi di richieste tra siti. Maggiori informazioni qui: en.wikipedia.org/wiki/Cross-site_request_forgery
Robert Harvey

1
sembra che ci sia una linea sottile tra la protezione di una domanda e il divieto di essere troppo ampia: D
anton1980

2
Da Cheat Sheet OWASP Prevenzione richiesta falsificazione (CSRF) : " Lo scripting tra siti non è necessario per far funzionare CSRF. Tuttavia, qualsiasi vulnerabilità di scripting tra siti può essere utilizzata per sconfiggere tutte le tecniche di mitigazione CSRF [...]. Questo perché un payload XSS può semplicemente leggere qualsiasi pagina del sito utilizzando XMLHttpRequest [...]. È indispensabile che non siano presenti vulnerabilità XSS per garantire che le difese CSRF non possano essere aggirate. "
toraritte

Risposte:


1497

Falso richiesta tra siti (CSRF) in parole semplici

  • Supponiamo che tu sia attualmente connesso al tuo banking online all'indirizzo www.mybank.com
  • Supponiamo che un trasferimento di denaro mybank.comcomporti una richiesta (concettualmente) del modulo http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>. (Il tuo numero di conto non è necessario, perché è implicito dal tuo login.)
  • Visiti www.cute-cat-pictures.org, senza sapere che si tratta di un sito dannoso.
  • Se il proprietario di quel sito conosce il modulo della richiesta di cui sopra (facile!) E indovina correttamente che hai effettuato l'accesso mybank.com(richiede un po 'di fortuna!), Potrebbe includere nella sua pagina una richiesta del tipo http://www.mybank.com/transfer?to=123456;amount=10000(dov'è 123456il numero del suo account Isole Cayman ed 10000è un importo che in precedenza pensavi di essere felice di possedere).
  • Hai recuperato quella www.cute-cat-pictures.orgpagina, quindi il tuo browser farà quella richiesta.
  • La tua banca non è in grado di riconoscere questa origine della richiesta: il tuo browser web invierà la richiesta insieme al tuo www.mybank.comcookie e sembrerà perfettamente legittimo. Ecco i tuoi soldi!

Questo è il mondo senza token CSRF .

Ora per quello migliore con i token CSRF :

  • La richiesta di trasferimento è esteso con un terzo argomento: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • Quel token è un numero casuale enorme, impossibile da indovinare che mybank.comincluderà sulla propria pagina web quando te lo servono. È diverso ogni volta che servono qualsiasi pagina a chiunque.
  • L'aggressore non è in grado di indovinare il token, non è in grado di convincere il browser Web a restituirlo (se il browser funziona correttamente ...), quindi l'attaccante non sarà in grado di creare una richiesta valida, poiché le richieste con il token errato (o nessun token) verrà rifiutato da www.mybank.com.

Risultato: mantieni le tue 10000unità monetarie. Ti suggerisco di donare parte di questo a Wikipedia.

(Il tuo chilometraggio può variare.)

MODIFICA dal commento che vale la pena leggere:

Sarebbe degno di nota che lo script www.cute-cat-pictures.orgnormalmente non ha accesso al token anti-CSRF a www.mybank.comcausa del controllo di accesso HTTP. Questa nota è importante per alcune persone che inviano irragionevolmente un'intestazione Access-Control-Allow-Origin: *per ogni risposta del sito Web senza sapere a cosa serve, solo perché non possono utilizzare l'API da un altro sito Web.


36
E ovviamente il token sarebbe idealmente chiamato token anti- CSRF, ma il nome è probabilmente abbastanza complicato come è.
Lutz Prechelt,

3
@LutzPrechelt grazie. perché javascript non è in grado di ottenere alcun token di autenticità dal browser?
BKSpurgeon,

72
Sarebbe degno di nota che lo script www.cute-cat-pictures.orgnormalmente non ha accesso al token anti-CSRF a www.mybank.comcausa del controllo di accesso HTTP. Questa nota è importante per alcune persone che inviano irragionevolmente un'intestazione Access-Control-Allow-Origin: *per ogni risposta del sito Web senza sapere a cosa serve, solo perché non possono utilizzare l'API da un altro sito Web.
SOF

9
@AugustinRiedinger Se l'attaccante apre la pagina Web sul suo computer - poiché non ha il cookie dell'utente che ha effettuato l'accesso - non riceverà il token csrf corrispondente (ogni token csrf dovrebbe essere valido solo per una sessione utente specifica). Se l'utente malintenzionato tenta di caricare la pagina Web contenente il token sul computer dell'utente, con uno script inserito nel sito Web cute-cat-pictures, il browser gli impedirà di leggere il sito www.mybank.com (e il token) a causa del stessa politica di origine.
Marcel,

13
@LutzPrechelt Penso che non sia sufficiente che il token sia sempre diverso, deve essere associato a una sessione e il server deve verificare che il token che riceve sia stato generato per una sessione identificata dal server dal cookie ricevuto. Altrimenti, l'hacker può semplicemente visitare mybank e ottenere un token valido. Quindi, se si utilizza un nuovo token con ogni modulo, è necessario salvarlo associato al sessionid sul server. Probabilmente è più facile usare lo stesso token per sessione.
Marcel

222

Sì, i dati dei post sono al sicuro. Ma l'origine di tali dati non lo è. In questo modo qualcuno può indurre l'utente con JS ad accedere al tuo sito mentre naviga nella pagina web dell'attaccante.

Per evitarlo, django invierà una chiave casuale sia nei cookie sia nei dati dei moduli. Quindi, quando i POST degli utenti verificheranno se due chiavi sono identiche. Nel caso in cui l'utente viene ingannato, il sito Web di terze parti non può ottenere i cookie del tuo sito, causando così un errore di autenticazione.


@DmitryShevchenko Ciao, stai cercando di capire in che modo questo metodo di cookie + form-input è diverso dal solo convalidare il referrer sul lato server? Tutti gli esempi che trovo sono legati a un hacker che inganna l'utente per pubblicare dal suo sito al sito reale.
Ethan,

Ok, ho scoperto perché il referrer non viene utilizzato. In molti casi è bloccato in quanto a volte è considerato contenere informazioni riservate. Le aziende e i loro delegati in genere lo fanno. Tuttavia, se si utilizza HTTPS, è più probabile che non venga bloccato.
Ethan,

4
È facile cambiare referrer, non direi che è un'informazione affidabile. Il token CSRF, tuttavia, viene generato utilizzando la chiave segreta del server e generalmente legato all'utente
Dmitry Shevchenko,

1
Non capisco davvero perché questa sia una minaccia alla sicurezza. L'utente accederà a un altro sito ... ma il sito originale non avrà alcun modo per recuperare tali informazioni. Giusto?
Aakil Fernandes,

6
Bene, supponiamo di inserire un iframe dannoso di " bank.com/transfer?from=x&to=y " in un, diciamo, Facebook.com. Se sei cliente di bank.com e vai su Facebook, quell'iframe caricherà la pagina della banca, con i tuoi cookie (perché il browser li invierà a un dominio noto) ed effettuerà un trasferimento di denaro. Senza che tu sappia nulla.
Dmitry Shevchenko,

74

Il sito genera un token univoco quando crea la pagina del modulo. Questo token è necessario per pubblicare / recuperare i dati sul server.

Poiché il token viene generato dal tuo sito e fornito solo quando viene generata la pagina con il modulo, alcuni altri siti non possono imitare i tuoi moduli: non avranno il token e quindi non potranno pubblicare sul tuo sito.


10
Un utente potrebbe afferrare l'output del token all'interno della sorgente, acquisire il cookie inviato a loro e quindi inviarlo da un sito di terze parti?
Jack Marchetti,

9
@JackMarchetti si. ma sarebbe costoso poiché ogni volta che si desidera inviare il modulo da un sito di terze parti, è necessario caricare la pagina e analizzare il token. I token CSRF dovrebbero essere accoppiati idealmente con altre forme di sicurezza se ti preoccupi di questo vettore di attacco
tkone,

4
Ho la stessa domanda di @JackMarchetti, non è chiaro se il token CSRF cambia ad ogni accesso. Se rimane lo stesso, cosa impedirebbe a un utente malintenzionato di accedere prima, afferrare il token di richiesta e quindi inserire quel token nell'attacco?
Paul Preibisch,

7
@PaulPreibisch dovrebbe cambiare ad ogni caricamento della pagina, non ad ogni accesso. In questo modo l'attaccante dovrebbe richiedere la pagina ogni volta che desidera inviare il modulo. Lo rende molto più difficile.
tkone

9
@tkone, Non rende davvero molto più difficile. Se solo raddoppia la quantità di sforzo e tempo. Non aggiunge alcun tipo di elaborazione proibitiva. Il trucco è anche associare il token CSRF a un cookie specifico del dominio e inviare questo cookie insieme al modulo. Sia i cookie che i dati del modulo devono essere inviati al server sulla richiesta POST. In questo modo sarebbe necessario un attacco di dirottamento dei cookie per poter emulare una richiesta legittima.
Pedro Cordeiro,

56

Il blog Cloud Under contiene una buona spiegazione dei token CSRF.

Immagina di avere un sito web come un Twitter semplificato, ospitato su a.com. Gli utenti che hanno effettuato l'accesso possono inserire del testo (un tweet) in un modulo che viene inviato al server come richiesta POST e pubblicato quando premono il pulsante di invio. Sul server l'utente viene identificato da un cookie contenente il proprio ID sessione univoco, in modo che il server sappia chi ha pubblicato il Tweet.

Il modulo potrebbe essere così semplice:

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

Ora immagina, un cattivo copia e incolla questo modulo sul suo sito Web dannoso, diciamo b.com. Il modulo funzionerebbe comunque. Finché un utente ha effettuato l'accesso al tuo Twitter (ovvero ha un cookie di sessione valido per a.com), la richiesta POST verrà inviata http://a.com/tweeted elaborata come al solito quando l'utente fa clic sul pulsante di invio.

Finora questo non è un grosso problema fino a quando l'utente viene a conoscenza di cosa fa esattamente il modulo, ma cosa succede se il nostro cattivo modifica il modulo in questo modo:

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

Ora, se uno dei tuoi utenti finisce sul sito del cattivo e colpisce il "Clicca per vincere!" pulsante, il modulo viene inviato al tuo sito Web, l'utente viene identificato correttamente dall'ID sessione nel cookie e il Tweet nascosto viene pubblicato.

Se il nostro cattivo fosse anche peggio, farebbe in modo che l'utente innocente inviasse questo modulo non appena aprisse la sua pagina web usando JavaScript, forse anche completamente nascosto in un iframe invisibile. Fondamentalmente si tratta di falsificazione di richieste tra siti.

Un modulo può essere facilmente inviato da qualsiasi luogo e ovunque. Generalmente è una funzionalità comune, ma ci sono molti altri casi in cui è importante consentire l'invio di un modulo solo dal dominio a cui appartiene.

Le cose vanno ancora peggio se la tua applicazione web non distingue tra richieste POST e GET (ad esempio in PHP usando $ _REQUEST invece di $ _POST). Non farlo! Le richieste di modifica dei dati potrebbero essere inviate con la stessa facilità <img src="http://a.com/tweet?tweet=This+is+really+bad">, incorporate in un sito Web dannoso o persino in un'e-mail.

Come posso assicurarmi che un modulo possa essere inviato solo dal mio sito Web? È qui che entra in gioco il token CSRF. Un token CSRF è una stringa casuale, difficile da indovinare. In una pagina con un modulo che desideri proteggere, il server genererebbe una stringa casuale, il token CSRF, lo aggiungerebbe al modulo come campo nascosto e lo ricorderebbe in qualche modo, memorizzandolo nella sessione o impostando un cookie contenente il valore. Ora il modulo sarebbe simile al seguente:

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

Quando l'utente invia il modulo, il server deve semplicemente confrontare il valore del campo registrato csrf-token (il nome non ha importanza) con il token CSRF ricordato dal server. Se entrambe le stringhe sono uguali, il server potrebbe continuare a elaborare il modulo. In caso contrario, il server dovrebbe interrompere immediatamente l'elaborazione del modulo e rispondere con un errore.

Perché funziona? Esistono diversi motivi per cui il cattivo del nostro esempio sopra non è in grado di ottenere il token CSRF:

Copiare il codice sorgente statico dalla nostra pagina su un sito Web diverso sarebbe inutile, perché il valore del campo nascosto cambia con ogni utente. Se il sito Web del malintenzionato non conosce il token CSRF dell'utente corrente, il server rifiuta sempre la richiesta POST.

Poiché la pagina dannosa del cattivo viene caricata dal browser dell'utente da un dominio diverso (b.com anziché a.com), il cattivo non ha alcuna possibilità di codificare un JavaScript, che carica il contenuto e quindi il token CSRF corrente del nostro utente da il tuo sito web. Questo perché i browser Web non consentono richieste AJAX tra domini per impostazione predefinita.

Anche il cattivo non è in grado di accedere al cookie impostato dal tuo server, perché i domini non corrisponderebbero.

Quando dovrei proteggermi dalla falsificazione di richieste tra siti? Se puoi assicurarti di non confondere GET, POST e altri metodi di richiesta come descritto sopra, un buon inizio sarebbe proteggere tutte le richieste POST per impostazione predefinita.

Non è necessario proteggere le richieste PUT e DELETE, poiché come spiegato sopra, un modulo HTML standard non può essere inviato da un browser utilizzando tali metodi.

JavaScript d'altra parte può effettivamente fare altri tipi di richieste, ad esempio utilizzando la funzione $ .ajax () di jQuery, ma ricorda, affinché le richieste AJAX funzionino i domini devono corrispondere (purché non configuri esplicitamente il tuo server web altrimenti) .

Ciò significa che spesso non è nemmeno necessario aggiungere un token CSRF alle richieste AJAX, anche se si tratta di richieste POST, ma è necessario assicurarsi di bypassare il controllo CSRF nell'applicazione Web solo se la richiesta POST è effettivamente un Richiesta AJAX. Puoi farlo cercando la presenza di un'intestazione come X-Requested-With, che di solito includono le richieste AJAX. È inoltre possibile impostare un'altra intestazione personalizzata e verificarne la presenza sul lato server. È sicuro, perché un browser non aggiungerebbe intestazioni personalizzate a un normale invio di moduli HTML (vedi sopra), quindi nessuna possibilità per Mr Bad Guy di simulare questo comportamento con un modulo.

In caso di dubbi sulle richieste AJAX, perché per qualche motivo non è possibile verificare un'intestazione come X-Requested-With, è sufficiente passare il token CSRF generato al JavaScript e aggiungere il token alla richiesta AJAX. Esistono diversi modi per farlo; aggiungerlo al payload proprio come farebbe un normale modulo HTML oppure aggiungere un'intestazione personalizzata alla richiesta AJAX. Finché il tuo server sa dove cercarlo in una richiesta in arrivo ed è in grado di confrontarlo con il valore originale che ricorda dalla sessione o dal cookie, sei ordinato.


Grazie per le informazioni dettagliate. Durante la richiesta di post, il sito deve inviare il token csrf al server, quindi quando il client invierà questo token csrf al server? È mentre si effettua la richiesta delle opzioni di verifica preliminare? Per favore elabora su questa parte ..
Sm Srikanth,

@Dan Come mai b.com può accedere ai cookie di un altro sito a.com?
zakir,

8

La radice di tutto è assicurarsi che le richieste provengano dagli utenti effettivi del sito. Un token csrf viene generato per i moduli e deve essere associato alle sessioni dell'utente. Viene utilizzato per inviare richieste al server, in cui il token le convalida. Questo è un modo per proteggere da csrf, un altro sarebbe controllare l'intestazione del referrer.


7
Non fare affidamento sull'intestazione del referer, può essere facilmente falsificato.
kag

3
Questa è la risposta corretta! Il token DEVE essere associato a una sessione sul server. Confrontare Cookie + dati del modulo come la risposta più votata suggerisce che è completamente sbagliato. Questi componenti fanno entrambi parte della richiesta, che il cliente costruisce.
Lee Davis,

3
In realtà no. Il token DEVE essere associato a ciascuna RICHIESTA al Server. Se lo colleghi solo alla sessione, corri il rischio che qualcuno rubi il token della sessione e invii una richiesta con quel token. Pertanto, per la massima sicurezza, il token deve essere associato a ciascun http richiesto.
chrisl08
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.