Condividi tramite


Prevenzione degli attacchi csrF (Cross-Site Request Forgery) in ASP.NET'applicazione MVC

Cross-Site Request Forgery (CSRF) è un attacco in cui un sito dannoso invia una richiesta a un sito vulnerabile in cui l'utente è attualmente connesso

Ecco un esempio di attacco CSRF:

  1. Un utente accede www.example.com usando l'autenticazione basata su form.

  2. Il server autentica l'utente. La risposta dal server include un cookie di autenticazione.

  3. Senza disconnettersi, l'utente visita un sito Web dannoso. Questo sito dannoso contiene il formato HTML seguente:

    <h1>You Are a Winner!</h1>
      <form action="http://example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
      <input type="submit" value="Click Me"/>
    </form>
    

    Si noti che l'azione modulo invia al sito vulnerabile, non al sito dannoso. Questa è la parte "cross-site" di CSRF.

  4. L'utente fa clic sul pulsante Invia. Il browser include il cookie di autenticazione con la richiesta.

  5. La richiesta viene eseguita nel server con il contesto di autenticazione dell'utente e può eseguire qualsiasi operazione consentita da un utente autenticato.

Anche se questo esempio richiede all'utente di fare clic sul pulsante del modulo, la pagina dannosa potrebbe eseguire facilmente uno script che invia automaticamente il modulo. Inoltre, l'uso di SSL non impedisce un attacco CSRF, perché il sito dannoso può inviare una richiesta "https://".

In genere, gli attacchi CSRF sono possibili contro siti Web che usano cookie per l'autenticazione, perché i browser inviano tutti i cookie pertinenti al sito Web di destinazione. Tuttavia, gli attacchi CSRF non sono limitati all'uso dei cookie. Ad esempio, anche l'autenticazione di base e digest è vulnerabile. Dopo che un utente accede con l'autenticazione Di base o Digest. il browser invia automaticamente le credenziali fino al termine della sessione.

Token antifalsificazione

Per evitare attacchi CSRF, ASP.NET MVC usa token antifalsificazione, detti anche token di verifica delle richieste.

  1. Il client richiede una pagina HTML contenente un modulo.
  2. Il server include due token nella risposta. Un token viene inviato come cookie. L'altro viene inserito in un campo modulo nascosto. I token vengono generati in modo casuale in modo che un avversario non possa indovinare i valori.
  3. Quando il client invia il modulo, deve inviare entrambi i token al server. Il client invia il token del cookie come cookie e invia il token del modulo all'interno dei dati del modulo. Un client del browser esegue automaticamente questa operazione quando l'utente invia il modulo.
  4. Se una richiesta non include entrambi i token, il server non consente la richiesta.

Di seguito è riportato un esempio di modulo HTML con un token di modulo nascosto:

<form action="/Home/Test" method="post">
    <input name="__RequestVerificationToken" type="hidden"   
           value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />    
    <input type="submit" value="Submit" />
</form>

I token antifalsificazione funzionano perché la pagina dannosa non è in grado di leggere i token dell'utente, a causa dei criteri di stessa origine. I criteri di stessa origine impediscono ai documenti ospitati in due siti diversi di accedere al contenuto dell'altro. Nell'esempio precedente la pagina dannosa può quindi inviare richieste a example.com, ma non può leggere la risposta.

Per evitare attacchi CSRF, usare token antifalsificazione con qualsiasi protocollo di autenticazione in cui il browser invia automaticamente le credenziali dopo l'accesso dell'utente. Sono inclusi protocolli di autenticazione basati su cookie, ad esempio l'autenticazione basata su moduli, nonché protocolli come l'autenticazione di base e digest.

È necessario richiedere token antifalsificazione per qualsiasi metodo non sicuro (POST, PUT, DELETE). Inoltre, assicurarsi che i metodi sicuri (GET, HEAD) non abbiano effetti collaterali. Inoltre, se si abilita il supporto tra domini, ad esempio CORS o JSONP, anche metodi sicuri come GET sono potenzialmente vulnerabili agli attacchi CSRF, consentendo all'utente malintenzionato di leggere dati potenzialmente sensibili.

Token antifalsificazione in ASP.NET MVC

Per aggiungere i token antifalsificazione a una pagina Razor, usare il metodo helper HtmlHelper.AntiForgeryToken :

@using (Html.BeginForm("Manage", "Account")) {
    @Html.AntiForgeryToken()
}

Questo metodo aggiunge il campo modulo nascosto e imposta anche il token del cookie.

Anti-CSRF e AJAX

Il token del modulo può essere un problema per le richieste AJAX, perché una richiesta AJAX potrebbe inviare dati JSON, non dati del modulo HTML. Una soluzione consiste nell'inviare i token in un'intestazione HTTP personalizzata. Il codice seguente usa la sintassi Razor per generare i token e quindi li aggiunge a una richiesta AJAX. I token vengono generati nel server chiamando AntiForgery.GetTokens.

<script>
    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
    }

    $.ajax("api/values", {
        type: "post",
        contentType: "application/json",
        data: {  }, // JSON data goes here
        dataType: "json",
        headers: {
            'RequestVerificationToken': '@TokenHeaderValue()'
        }
    });
</script>

Quando si elabora la richiesta, estrarre i token dall'intestazione della richiesta. Chiamare quindi il metodo AntiForgery.Validate per convalidare i token. Il metodo Validate genera un'eccezione se i token non sono validi.

void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}