Cos’è un token CSRF? Qual è la sua importanza e come funziona?

Ok ragazzi, sto scrivendo un’applicazione Django e voglio solo un’idea di cosa sia effettivamente un token csrf e di come protegge i dati. I dati dei post non sono sicuri se non si utilizzano i token csrf?

So come usare csrf_token ma ho solo bisogno di alcune informazioni su come funziona.

Cross-Site Request Forgery (CSRF) in parole semplici

  • Supponiamo che tu sia attualmente collegato al tuo banking online su www.mybank.com
  • Si supponga che un trasferimento di denaro da mybank.com comporterà una richiesta (concettualmente) del modulo http://www.mybank.com/transfer?to=;amount= . (Il tuo numero di conto non è necessario, perché è implicito dal tuo login.)
  • Visiti www.cute-cat-pictures.org , non sapendo che si tratta di un sito malevolo.
  • Se il proprietario di quel sito conosce la forma della richiesta di cui sopra (facile!) E indovina correttamente di aver effettuato l’accesso a mybank.com (richiede un po ‘di fortuna!), Potrebbero includere nella loro pagina una richiesta come http://www.mybank.com/transfer?to=123456;amount=10000 (dove 123456 è il numero del loro account Cayman Islands e 10000 è un importo che in precedenza pensavate di essere contento di possedere).
  • Hai recuperato quella pagina www.cute-cat-pictures.org , così il tuo browser farà quella richiesta.
  • La tua banca non è in grado di riconoscere questa origine della richiesta: il tuo browser invierà la richiesta insieme al tuo cookie www.mybank.com e apparirà perfettamente legittimo. Ecco i tuoi soldi!

Questo è il mondo senza gettoni CSRF .

Ora per il meglio con i token CSRF :

  • La richiesta di trasferimento viene estesa con un terzo argomento: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971 .
  • Questo token è un numero casuale enorme, imansible da indovinare che mybank.com includerà nella propria pagina web quando lo servirà a te. È diverso ogni volta che servono una pagina a qualcuno.
  • L’autore dell’attacco non è in grado di indovinare il token, non è in grado di convincere il tuo browser Web a rinunciarlo (se il browser funziona correttamente …), e quindi l’utente malintenzionato non sarà in grado di creare una richiesta valida, perché le richieste con il token errato (o nessun token) verrà rifiutato da www.mybank.com .

Risultato: mantieni le tue 10000 unità monetarie. Ti suggerisco di donarne un po ‘a Wikipedia.

(Il tuo chilometraggio può variare).

EDIT da commento vale la pena leggere:

Sarebbe degno di nota che lo script di www.cute-cat-pictures.org normalmente non ha accesso al tuo token anti-CSRF da www.mybank.com causa 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.

Sì, i dati del post sono al sicuro. Ma l’origine di quei dati non lo è. In questo modo, qualcuno può ingannare l’utente con JS per accedere al tuo sito, mentre sta navigando nella pagina web dell’attaccante.

Per evitare ciò, django invierà una chiave casuale sia nei cookie che nei dati del modulo. Quindi, quando gli utenti POST, controllerà se due chiavi sono identiche. Nel caso in cui l’utente venga ingannato, il sito Web di terze parti non può ottenere i cookie del tuo sito, causando così un errore di autenticazione.

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

Poiché il token viene generato dal tuo sito e viene fornito solo quando viene generata la pagina con il modulo, un altro sito non può imitare i tuoi moduli: non avranno il token e quindi non potranno pubblicare sul tuo sito.

La radice di tutto ciò è 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 di proteggere da csrf, un altro dovrebbe controllare l’intestazione del referrer.

Lasciate che vi faccia un esempio…

Immagina di avere un sito web come un Twitter semplificato, ospitato su a.com. Gli utenti registrati 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 che contiene il proprio ID di sessione univoco, quindi il server sa chi ha pubblicato il tweet.

La forma potrebbe essere così semplice:

  

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

Finora questo non è un grosso problema se l’utente viene informato su cosa fa esattamente il modulo, ma cosa succede se il nostro cattivo aggiusta il modulo in questo modo:

  

Ora, se uno dei tuoi utenti finisce sul sito web del cattivo e fa clic sul pulsante “Clicca per vincere!”, Il modulo viene inviato al tuo sito web, l’utente viene identificato correttamente dall’ID di sessione nel cookie e il Tweet nascosto viene pubblicato.

Se il nostro cattivo era ancora peggio, avrebbe fatto 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. Questo in pratica è una falsificazione di richieste cross-site.

Un modulo può essere facilmente inviato da ovunque a ovunque. Generalmente questa è una caratteristica comune, ma ci sono molti altri casi in cui è importante consentire solo un modulo inviato dal dominio a cui appartiene.

Le cose vanno anche peggio se la tua applicazione web non distingue tra le 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à del http://a.com/tweet?tweet=This+is+really+bad , incorporate in un sito Web dannoso o addirittura in un’email.

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 e difficile da indovinare. Su una pagina con un modulo che si desidera proteggere, il server genera una stringa casuale, il token CSRF, lo aggiunge al modulo come campo nascosto e lo ricorda anche in qualche modo, memorizzandolo nella sessione o impostando un cookie contenente il valore. Ora il modulo dovrebbe assomigliare a questo:

  

Quando l’utente invia il modulo, il server deve semplicemente confrontare il valore del campo inviato csrf-token (il nome non ha importanza) con il token CSRF memorizzato dal server. Se entrambe le stringhe sono uguali, il server può continuare a elaborare il modulo. Altrimenti il ​​server dovrebbe interrompere immediatamente l’elaborazione del modulo e rispondere con un errore.

Perché funziona? Ci sono diversi motivi per cui il cattivo dell’esempio precedente non è in grado di ottenere il token CSRF:

Copiare il codice sorgente statico dalla nostra pagina su un altro sito Web sarebbe inutile, perché il valore del campo nascosto cambia con ciascun utente. Senza il sito Web del cattivo, conoscendo il token CSRF dell’utente corrente, il server rifiuterà sempre la richiesta POST.

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

Anche il cattivo non può accedere al set di cookie dal tuo server, perché i domini non corrispondono.

Quando dovrei proteggere contro la falsificazione di richieste cross-site? Se è ansible assicurarsi di non confondere GET, POST e altri metodi di richiesta come descritto sopra, un buon inizio sarebbe quello di proteggere tutte le richieste POST per impostazione predefinita.

Non è necessario proteggere le richieste PUT e DELETE perché, 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, per le richieste AJAX di funzionare, i domini devono corrispondere (se non si configura diversamente il server web in altro modo) .

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 nella propria 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 include le richieste AJAX. È anche ansible impostare un’altra intestazione personalizzata e verificare la presenza sul lato server. Questo è 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 è ansible verificare un’intestazione come X-Requested-With, basta passare il token CSRF generato al proprio JavaScript e aggiungere il token alla richiesta AJAX. Ci sono diversi modi per farlo; o aggiungilo al payload proprio come farebbe un normale modulo HTML, o 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.