Prevence útoků CSRF (Cross-Site Request Forgery) v aplikaci ASP.NET MVC

Útok CSRF (Cross-Site Request Forgery) je útok, kdy škodlivý web odešle požadavek na ohrožený web, na kterém je uživatel aktuálně přihlášený.

Tady je příklad útoku CSRF:

  1. Uživatel se přihlašuje pomocí www.example.com ověřování pomocí formulářů.

  2. Server ověří uživatele. Odpověď ze serveru obsahuje ověřovací soubor cookie.

  3. Bez odhlášení uživatel navštíví škodlivý web. Tento škodlivý web obsahuje následující formulář HTML:

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

    Všimněte si, že akce formuláře odešle příspěvek na ohrožený web, ne na škodlivý web. Toto je část CSRF "mezi weby".

  4. Uživatel klikne na tlačítko Odeslat. Prohlížeč do požadavku zahrne ověřovací soubor cookie.

  5. Požadavek se spustí na serveru s kontextem ověřování uživatele a může provádět cokoliv, co má ověřený uživatel povoleno.

I když tento příklad vyžaduje, aby uživatel klikl na tlačítko formuláře, škodlivá stránka by mohla stejně snadno spustit skript, který odešle formulář automaticky. Navíc použití PROTOKOLU SSL nezabrání útoku CSRF, protože škodlivý web může odeslat požadavek na "https://".

Útoky CSRF jsou obvykle možné na weby, které k ověřování používají soubory cookie, protože prohlížeče odesílají všechny relevantní soubory cookie na cílový web. Útoky CSRF se však neomezují pouze na zneužití souborů cookie. Například základní ověřování a ověřování hodnotou hash jsou také ohroženy. Poté, co se uživatel přihlásí pomocí základního ověřování nebo ověřování hodnotou hash. prohlížeč automaticky odesílá přihlašovací údaje, dokud relace neskončí.

Tokeny proti padělání

Aby se zabránilo útokům CSRF, ASP.NET MVC používá tokeny proti padělání, označované také jako tokeny pro ověření požadavků.

  1. Klient si vyžádá stránku HTML, která obsahuje formulář.
  2. Server do odpovědi zahrne dva tokeny. Jeden token se odešle jako soubor cookie. Druhý se umístí do skrytého pole formuláře. Tokeny se generují náhodně, aby nežádoucí osoba nemohla hodnoty uhodnout.
  3. Když klient odešle formulář, musí odeslat oba tokeny zpět na server. Klient odešle token souboru cookie jako soubor cookie a token formuláře odešle uvnitř dat formuláře. (Klient prohlížeče to udělá automaticky, když uživatel odešle formulář.)
  4. Pokud požadavek neobsahuje oba tokeny, server požadavek zakáže.

Tady je příklad formuláře HTML se skrytým tokenem formuláře:

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

Tokeny proti padělání fungují, protože škodlivá stránka nemůže číst tokeny uživatele kvůli zásadám stejného původu. (Zásady stejného původu brání dokumentům hostovaným na dvou různých webech v přístupu k obsahu ostatních. Takže v předchozím příkladu může škodlivá stránka odesílat požadavky example.com, ale nemůže přečíst odpověď.)

Pokud chcete útokům CSRF zabránit, použijte tokeny proti padělání s libovolným ověřovacím protokolem, kdy prohlížeč bezobslužně odesílá přihlašovací údaje po přihlášení uživatele. To zahrnuje ověřovací protokoly založené na souborech cookie, jako je ověřování pomocí formulářů, a protokoly jako základní ověřování a ověřování hodnotou hash.

Tokeny proti padělání byste měli vyžadovat pro všechny metody, které nejsou bezpečné (POST, PUT, DELETE). Také se ujistěte, že bezpečné metody (GET, HEAD) nemají žádné vedlejší účinky. Pokud navíc povolíte podporu mezi doménami, jako je CORS nebo JSONP, pak i bezpečné metody, jako je GET, jsou potenciálně zranitelné vůči útokům CSRF, což útočníkovi umožní číst potenciálně citlivá data.

Tokeny proti padělání v ASP.NET MVC

Pokud chcete přidat tokeny proti padělání na stránku Razor, použijte metodu pomocné rutiny HtmlHelper.AntiForgeryToken :

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

Tato metoda přidá skryté pole formuláře a také nastaví token souboru cookie.

Anti-CSRF a AJAX

Token formuláře může být pro požadavky AJAX problémem, protože požadavek AJAX může odesílat data JSON, nikoli data formuláře HTML. Jedním z řešení je odeslání tokenů ve vlastní hlavičce HTTP. Následující kód používá syntaxi Razor k vygenerování tokenů a pak tokeny přidá do požadavku AJAX. Tokeny jsou generovány na serveru voláním 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>

Při zpracování požadavku extrahujte tokeny z hlavičky požadavku. Pak volání AntiForgery.Validate metoda ověřit tokeny. Metoda Validate vyvolá výjimku, pokud tokeny nejsou platné.

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