Cross-site request forgery (CSRF)
Una Cross-site Request Forgery (CSRF) è una vulnerabilità che fornisce a un attaccante un modo per indurre un utente a compiere delle azioni che non intendevano compiere. Dipendentemente da come l'applicazione è costruita, una CSRF può permettere all'attaccante di modificare le credenziali di un utente, effettuare degli acquisti da parte dello stesso e compromettere completamente l'applicazione stessa.
Affinché un attacco CSRF sia possibile e rilevante, devono verificarsi le seguenti tre condizioni.
- Deve esistere un'azione all'interno del contesto del sito che l'attaccante abbia interesse a indurre, come ad esempio un cambio di password, di mail, l'effettuazione di un trasferimento monetario o simili.
- La sessione deve essere creata solo mediante i cookie, e l'azione da indurre deve essere riproducibile attraverso una o più richieste HTTP
- Non devono essere necessari parametri non predicibili all'interno delle richieste HTTP da effettuare affinché l'azione indotta vada a buon fine
Esempio di CSRF
Supponiamo di avere un endpoint /emailchange che permette a un utente autenticato di cambiare la propria mail
La richiesta POST da inviare affinché la mail venga cambiata è la seguente:
POST /emailchange HTTP/1.1
Host: random-site.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: session=[session cookie]
nuova_email=example@gmail.com
Un attaccante potrebbe indurre un utente a visitare il proprio sito contenente la seguente pagina HTML:
<html>
<body>
<form action="https://random-site.com/emailchange" method="POST">
<input type="hidden" name="nuova_email" value="attacker_email@evil-user.net" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Supponendo che l'utente attaccato sia autenticato su random-site.com, verrebbe inviata una richiesta "a nome" dell'utente attaccato la cui mail verrebbe cambiata in una mail controllata dall'attaccante.
Questo è possibile perché per adesso non teniamo conto dell'attributo SameSite dei cookie, di cui parleremo successivamente.
Difese tipiche contro CSRF
Una difesa tipica applicata contro gli attacchi di tipo CSRF è l'introduzione di un CSRF token, ovvero un valore unico, segreto e non predicibile generato dal server e condiviso con il client, che viene inviato insieme alle richieste effettuate dal client e controllato dal server per decidere se effettuare o meno l'azione richiesta.
Questo va a invalidare la terza condizione necessaria per effettuare un attacco CSRF: un attaccante dovrebbe essere in grado prima di recuperare il CSRF token e successivamente di indurre l'utente a visitare la pagina con il payload che includa anche il CSRF token recuperato.
Sono possibili anche altre difese, come l'utilizzo di cookie SameSite, oppure l'applicazione di protezioni referer-based.
Mitigazioni: CSRF token
Il modo più robusto per proteggere un'applicazione da attacchi CSRF è l'utilizzo dei CSRF token. Un token deve avere le seguenti proprietà per essere efficace:
- Essere impredicibile con un'alta entropia
- Essere legato alla sessione utente
- Essere validato ogni volta che viene richiesta un'azione rilevante
Generazione del token
Per la generazione del token è necessario utilizzare un generatore di numeri pseudo-casuali crittograficamente sicuro, utilizzando come seed un segreto e il timestamp di creazione.
Trasmissione del token
I token devono essere trattati come segreti ed essere gestiti in modo sicuro per tutto il loro ciclo di vita. L'approccio classico alla trasmissione di questi token consiste nell'inserirli all'interno di un input nascosto nei form presenti nella pagina richiesta; in questo modo il token viene inviato a ogni sottomissione delle form. Un altro accorgimento consiste nel posizionare l'input nascosto prima di tutti gli altri, specialmente prima da input tag che possono contenere input utente, in modo da mitigare attacchi in cui un utente malevolo può manipolare parti del contenuto HTML della pagina, come ad esempio dangling markup.
Validazione del token
Una volta generato, il token va memorizzato lato server associato alla sessione dell'utente per cui è stato creato. Quando un richiesta successiva che necessita di validazione viene ricevuta dal server, è necessario verificare che il token inviato dal client corrisponda con quello memorizzato, indipendentemente dal metodo e dal content-type della richiesta. Una richiesta che non contiene il token deve essere scartata esattamente come se fosse una richiesta contenente un token non valido.
Vi possono però essere dei difetti nella vlaidazione dei CSRF token che permettono a un attaccante di aggirarne il meccanismo.
- La validazione del token dipende dal metodo: se vi sono delle richieste GET che modificano lo stato dell'applicazione, ma il CSRF token viene controllato solo nelle richieste POST, un attaccante potrebbe indurre un utente a effettuare tale richiesta aggirando completamente il meccanismo di controllo del CSRF token.
- La validazione del token dipende dalla presenza del token stesso: se il meccanismo di controllo del token viene utilizzato solo se il token è presente nella richiesta, ma ignorato in caso contrario, un attaccante può ignorarne completamente la presenza
- Il token non è legato alla sessione: se il token CSRF non è legato alla sessione dell'utente, un attaccante potrebbe registrarsi e utilizzare il proprio CSRF token nella richiesta indotta alla vittima; il CSRF token sarebbe valido e la richiesta avrebbe successo, impattando però la vittima identificata dal cookie di sessione.
Protezioni Referer base
Alcune applicazioni possono fare uso dell'header Referer per difendersi da attacchi CSRF, solitamente verificando che la richiesta provenga dal dominio dell'applicazione stessa.
L'header Referer è un header opzionale del protocollo HTTP che contiene l'URL della pagina web che ha effettuato la richiesta; viene solitamente aggiunto dal browser. Per motivi di privacy esistono modi per modificarne il valore.
Mitigazioni ulteriori
In generale, è consigliato utilizzare cookie con attributo SameSite=Strict ogni volta possibile, e rilassarne la protezione a Lax solo se necessario.
È fortemente sconsigliato utilizzare cookie con attributo SameSite=None se non si è pienamente consapevole delle implicazioni di sicurezza che ne possono scaturire.