È necessario che il token sia inviato nella richiesta all'esterno del meccanismo dei cookie (ad esempio dati POST). Se le sessioni vengono gestite tramite un ID sessione contenuto in un cookie, il tuo approccio non impedisce CSRF.
Nella tua attuale implementazione:
- save token to session;
- save token to client's cookie via Set-Cookie header.
Questo avrà l'effetto di salvare il token in due posizioni, ma entrambe le posizioni saranno identificate dai valori del cookie.
es. se il token è " 12345678
" verrà salvato in sessione (pseudocodice):
Session["SessionCSRFToken"] = "12345678";
e nei cookie
Cookies.Add("CSRFToken", "12345678");
Tuttavia, al fine di salvare il valore in sessione, il framework dell'applicazione web creerà un cookie per identificare la sessione, in modo da ottenere due cookie impostati:
Set-Cookie: CSRFToken=12345678;
Set-Cookie: SessionID=987654321;
Se un utente accede al tuo sito web a www.foo.com
e poi l'utente visita www.evil.com
, potrebbe esserci un tag form
nascosto incorporato nella pagina di www.evil.com
(possibilmente all'interno di un IFrame nascosto) che è automaticamente inviato da JavaScript:
<form method="post" action="https://www.foo.com/Account/DeleteAccount">
</form>
Quando il browser invia automaticamente il modulo, entrambi i cookie verranno inviati insieme alla richiesta
( CSRFToken=12345678
, SessionID=987654321
) e il token cookie ( CSRFToken
) e il token di sessione ( SessionCSRFToken
) corrisponderanno e l'effetto sarà che l'account dell'utente viene chiuso sul tuo sistema a loro insaputa.
Per impedire ciò, è necessario memorizzare un token CSRF nella pagina stessa (ad esempio all'interno di un input nascosto). In questo modo il tuo modulo può essere inviato solo come segue:
<form method="post" action="/Account/DeleteAccount">
<input type="hidden" name="CSRFToken" value="12345678" />
</form>
Ora www.evil.com
non ha modo di includere l'input nascosto nel proprio codice HTML in quanto non ha modo di conoscere il valore di CSRFToken
. Il valore di CSRFToken
può essere lo stesso del cookie (il valore della sessione non è più necessario), ma deve essere generato solo una volta la sessione utente (non è necessario rigenerare costantemente il valore).
Per ogni POST
devi semplicemente assicurarti che Request.Form["CSRFToken"] == Request.Cookies("CSRFToken")
.