Förhindra Cross-Site Request Forgery (CSRF) i ASP.NET MVC-applikation

Förfalskning av begäranden mellan webbplatser (CSRF) är en attack där en skadlig webbplats skickar en begäran till en sårbar webbplats där användaren för närvarande är inloggad

Här är ett exempel på en CSRF-attack:

  1. En användare loggar in www.example.com med formulärautentisering.

  2. Servern autentiserar användaren. Svaret från servern innehåller en autentiseringscookie.

  3. Utan att logga ut besöker användaren en skadlig webbplats. Den här skadliga webbplatsen innehåller följande HTML-formulär:

    <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>
    

    Observera att formuläråtgärden skickas till den sårbara webbplatsen, inte till den skadliga webbplatsen. Det här är "cross-site"-delen av CSRF.

  4. Användaren klickar på knappen Skicka. Webbläsaren innehåller autentiseringscookien med begäran.

  5. Begäran körs på servern med användarens autentiseringskontext och kan göra allt som en autentiserad användare får göra.

Även om det här exemplet kräver att användaren klickar på formulärknappen kan den skadliga sidan lika enkelt köra ett skript som skickar formuläret automatiskt. Dessutom förhindrar inte användning av SSL en CSRF-attack, eftersom den skadliga webbplatsen kan skicka en "https://"-begäran.

Normalt är CSRF-attacker möjliga mot webbplatser som använder cookies för autentisering, eftersom webbläsare skickar alla relevanta cookies till målwebbplatsen. CSRF-attacker är dock inte begränsade till att utnyttja cookies. Till exempel är grundläggande och sammanfattad autentisering också sårbara. När en användare har loggat in med Basic- eller Digest-autentisering. webbläsaren skickar automatiskt autentiseringsuppgifterna tills sessionen avslutas.

Antiförfalskningstoken

För att förhindra CSRF-attacker använder ASP.NET MVC antiförfalskningstoken, även kallat verifieringstoken för begäran.

  1. Klienten begär en HTML-sida som innehåller ett formulär.
  2. Servern inkluderar två tokens i svaret. En token skickas som en cookie. Den andra placeras i ett dolt formulärfält. Token genereras slumpmässigt så att en angripare inte kan gissa värdena.
  3. När klienten skickar formuläret måste båda token skickas tillbaka till servern. Klienten skickar cookietoken som en cookie och skickar formulärtoken i formulärdata. (En webbläsarklient gör detta automatiskt när användaren skickar formuläret.)
  4. Om en begäran inte innehåller båda token tillåter servern inte begäran.

Här är ett exempel på ett HTML-formulär med en dold formulärtoken:

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

Anti-förfalskningstoken fungerar eftersom den skadliga sidan inte kan läsa användarens token på grund av same-origin-policy. (Principer för samma ursprung hindrar dokument som finns på två olika webbplatser från att komma åt varandras innehåll. Så i det tidigare exemplet kan den skadliga sidan skicka begäranden till example.com, men den kan inte läsa svaret.)

För att förhindra CSRF-attacker använder du antiförfalskningstoken med alla autentiseringsprotokoll där webbläsaren tyst skickar autentiseringsuppgifter efter att användaren har loggat in. Detta inkluderar cookiebaserade autentiseringsprotokoll, till exempel formulärautentisering, samt protokoll som grundläggande och sammanfattad autentisering.

Du måste kräva antiförfalsknings-token för alla osäkra metoder (POST, PUT, DELETE). Se också till att säkra metoder (GET, HEAD) inte har några biverkningar. Om du aktiverar stöd mellan domäner, till exempel CORS eller JSONP, är även säkra metoder som GET potentiellt sårbara för CSRF-attacker, vilket gör att angriparen kan läsa potentiellt känsliga data.

Anti-förfalskningstoken i ASP.NET MVC

Om du vill lägga till förfalskningstokens på en Razor-sida använder du hjälpmetoden HtmlHelper.AntiForgeryToken :

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

Den här metoden lägger till det dolda formulärfältet och anger även cookietoken.

Anti-CSRF och AJAX

Formulärtoken kan vara ett problem för AJAX-begäranden eftersom en AJAX-begäran kan skicka JSON-data, inte HTML-formulärdata. En lösning är att skicka token i ett anpassat HTTP-huvud. Följande kod använder Razor-syntax för att generera token och lägger sedan till token i en AJAX-begäran. Token genereras på servern genom att anropa 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>

När du bearbetar begäran extraherar du token från begärandehuvudet. Anropa sedan metoden AntiForgery.Validate för att verifiera token. Metoden Validate utlöser ett undantag om token inte är giltiga.

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);
}