CSRF o XSRF è uno dei più noti attacchi informatici che possono essere diretti a qualsiasi sito web, indipendentemente dalla tecnologia di backend. Una grande percentuale di siti, infatti, non sono protetti nei confronti di questo tipo di attacco o possiedono delle pagine vulnerabili facilmente individuabili da un attaccante.
La vittima di un attacco CSRF è quasi sempre l’utente. L’attacco sfrutta l’assunto che le operazioni fatte da un browser web, all’interno di una sessione autenticata, corrispondono sempre a richieste fatte esplicitamente dall’utente. Si tratta di un assunto molto rischioso perché facilmente sfruttabile da un attaccante che, indirizzando l’utente su un sito creato ad hoc, riesce a comandarne il browser con l’utilizzo di javascript.
Solitamente, l’utente viene reindirizzato verso una pagina web ospitata su un sito diverso da quello su cui è diretto l’attacco. La pagina malevola contiene del codice javascript (è possibile fare anche a meno di javascript) che invia dei dati al sito attaccato senza che l’utente ne venga a conoscenza. Il sito attaccato, perché utilizza un sistema di autenticazione basato su cookie, o perché l’utente si era precedentemente autenticato, accetta l’identità dell’utente ed esegue le operazioni come se fossero state richieste esplicitamente.
L’esempio tipico che viene fatto è quello del sito di una banca non protetto da CSRF. Un attaccante potrebbe eseguire un bonifico verso il proprio conto senza che l’utente se ne accorga (e, ovviamente, senza il suo permesso).
Esistono vari metodi per proteggere un sito web dall’attacco CSRF. I principali sono due:
- Controllo dell’header “Referer” della richiesta HTTP;
- Utilizzo del pattern “synchronizer token”.
La protezione di un sito web mediante controllo dell’header “Referer” è molto semplice da implementare. Il controllo consiste nel bloccare tutte le richieste che provengono da altri siti. L’header “Referer” serve appunto a determinare la provenienza della richiesta HTTP.
Questo tipo di protezione, però, presenta degli inconvenienti di cui bisogna tener conto. Oltre al fatto che esistono molti browser che non inviano questo header, o permettono all’utente di disabilitarne l’invio, bisogna considerare che tutte le volte che si fa click su un link presente su applicazioni esterne, quali Google Talk, Skype etc. o quando si copia un link e lo si incolla direttamente nella barra degli indirizzi del browser, il browser non invia questo header perché non saprebbe come riempirlo ().
Bisogna, inoltre, considerare che bloccare tutte le richieste provenienti da altri siti potrebbe essere dannoso, perché nessuno potrebbe creare dei link verso il nostro sito (ed i link sono fondamentali per l’indicizzazione nei motori di ricerca).
Una buona prassi è quella di fare buon uso dei metodi di richiesta HTTP all’interno delle pagine del sito, per poi proteggere attraverso il controllo del “Referer” solo le richieste NON idempotenti. Fare un buon uso dei metodi, significa assicurarsi che tutte le richieste che modificano i dati avvengano con metodi HTTP POST, PUT, DELETE e, soprattutto, che le stesse richieste non possano essere eseguite utilizzano GET, HEAD etc.
Con questa configurazione, la vulnerabilità CSRF sarebbe eliminata ma, non funzionerebbero le richieste senza header “Referer”, magari perché non inviato dal browser (o da un proxy).
Il metodo consigliato per la prevenzione degli attacchi CSRF è un altro, ma il suo impiego richiede degli sforzi maggiori. Il metodo del “synchronizer token” consiste nell’inserire una stringa casuale in tutte le richieste HTTP inviate al sito WEB. La stringa casuale deve essere unica per sessione utente e deve essere impossibile per un attaccante riuscire ad indovinarla.
Anche qui, proteggere tutte le pagine potrebbe portare a dei problemi (e a dei rischi). I link verso il sito non funzionerebbero, perché non contengono il token. Se l’utente salva una pagina nei preferiti, dopo qualche tempo il link (che contiene il token di sincronizzazione) non funzionerebbe più. Cosa ancora più grave, se l’utente fa click su un link diretto ad un sito malevolo, invierà (attraverso l’header “Referer”) l’indirizzo della pagina da cui proviene, comprensivo del token di accesso !
La soluzione più opportuna, quindi, sembra quella di richiedere il token solo per le richieste NON idempotenti (nelle richieste POST, i parametri passati al server non sono visibili nella query string dell’URL…).
Le due soluzioni possono essere usate contemporaneamente per una protezione maggiore. Ad esempio si può applicare un filtro misto su tutte le richieste non idempotenti che blocchi le richieste che non provengono da siti esterni e che, in caso di “Referer” assente, applichi il controllo token (il controllo token potrebbe essere eseguito anche se si supera il controllo “Referer”).
Nei prossimi giorni pubblicherò i dettagli di una nuova libreria che permette l’implementazione di tutti questi controlli in maniera molto semplice e utilizzando un file di configurazione XML: il progetto Sea Surf (Java EE 6).