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?
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?
Risposte:
www.mybank.com
mybank.com
comporti 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.)www.cute-cat-pictures.org
, senza sapere che si tratta di un sito dannoso.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'è 123456
il numero del suo account Isole Cayman ed 10000
è un importo che in precedenza pensavi di essere felice di possedere).www.cute-cat-pictures.org
pagina, quindi il tuo browser farà quella richiesta.www.mybank.com
cookie e sembrerà perfettamente legittimo. Ecco i tuoi soldi!Questo è il mondo senza token CSRF .
Ora per quello migliore con i token CSRF :
http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
.mybank.com
includerà sulla propria pagina web quando te lo servono. È diverso ogni volta che servono qualsiasi pagina a chiunque.www.mybank.com
.Risultato: mantieni le tue 10000
unità 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.org
normalmente non ha accesso al token anti-CSRF a 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.
www.cute-cat-pictures.org
normalmente non ha accesso al token anti-CSRF a 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 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.
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.
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/tweet
ed 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.
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.