Prevence útoků XSRF/CSRF (Cross-Site Request Forgery) v ASP.NET Core

Fiyaz Hasan a Rick Anderson

Padělání požadavků mezi weby je útok na aplikace hostované na webu, kdy škodlivá webová aplikace může ovlivnit interakci mezi klientským prohlížečem a webovou aplikací, která důvěřuje danému prohlížeči. Tyto útoky jsou možné, protože webové prohlížeče automaticky odesílají některé typy ověřovacích tokenů s každou žádostí na web. Tato forma zneužití se také označuje jako útok jedním kliknutím nebo jízda na relaci, protože útok využívá dříve ověřenou relaci uživatele. Padělání požadavků mezi weby se také označuje jako XSRF nebo CSRF.

Příklad útoku CSRF:

  1. Uživatel se www.good-banking-site.example.com přihlásí pomocí ověřování pomocí formulářů. Server ověřuje uživatele a vydává odpověď, která zahrnuje ověřování cookie. Web je zranitelný vůči útoku, protože důvěřuje všem požadavkem, který obdrží s platným ověřováním cookie.

  2. Uživatel navštíví škodlivý web. www.bad-crook-site.example.com

    Škodlivý web obsahuje www.bad-crook-site.example.comformulář HTML podobný následujícímu příkladu:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Všimněte si, že příspěvky formuláře action na ohrožený web, ne na škodlivý web. Toto je "cross-site" část CSRF.

  3. Uživatel vybere tlačítko Odeslat. Prohlížeč vytvoří požadavek a automaticky zahrne ověřování cookie pro požadovanou doménu. www.good-banking-site.example.com

  4. Požadavek se spustí na www.good-banking-site.example.com serveru s kontextem ověřování uživatele a může provést jakoukoli akci, kterou může ověřený uživatel provést.

Kromě scénáře, ve kterém uživatel vybere tlačítko pro odeslání formuláře, může škodlivý web:

  • Spusťte skript, který automaticky odešle formulář.
  • Odešlete formulář jako požadavek AJAX.
  • Skryjte formulář pomocí šablon stylů CSS.

Tyto alternativní scénáře nevyžadují žádnou akci ani vstup od jiného uživatele, než je počáteční návštěva škodlivého webu.

Použití PROTOKOLU HTTPS nezabrání útoku CSRF. Škodlivý web může požadavek odeslat https://www.good-banking-site.com/ stejně snadno, jako by mohl odeslat nezabezpečený požadavek.

Některé cílové koncové body útoků, které reagují na požadavky GET, v takovém případě je možné k provedení akce použít značku image. Tato forma útoku je běžná na webech fóra, které umožňují obrázky, ale blokují JavaScript. Aplikace, které mění stav požadavků GET, kde se mění proměnné nebo prostředky, jsou zranitelné vůči škodlivým útokům. Požadavky GET, které změní stav, jsou nezabezpečené. Osvědčeným postupem je nikdy změnit stav požadavku GET.

Útoky CSRF jsou možné vůči webovým aplikacím, které používají cookieověřování, protože:

  • cookieÚložiště prohlížečů vydané webovou aplikací
  • Uložené cookierelace cookiezahrnutí pro ověřené uživatele.
  • Prohlížeče odesílají všechny soubory cookiepřidružené k doméně do webové aplikace bez ohledu na to, jak se požadavek na aplikaci vygeneroval v prohlížeči.

Útoky CSRF se ale neomezují pouze na zneužití cookie. Například základní ověřování a ověřování hodnotou hash je také ohroženo. Jakmile se uživatel přihlásí pomocí ověřování Basic nebo Digest, prohlížeč automaticky odešle přihlašovací údaje, dokud relace nedokončí.

V tomto kontextu relace odkazuje na relaci na straně klienta, během které je uživatel ověřen. Nesouvisí s relacemi na straně serveru nebo se ASP.NET Middleware základní relace.

Uživatelé mohou chránit před ohroženími zabezpečení CSRF tím, že podniknou opatření:

  • Po dokončení se odhlaste z webových aplikací.
  • Pravidelně vymažte prohlížeč cookie.

Ohrožení zabezpečení CSRF jsou ale v zásadě problém s webovou aplikací, nikoli koncovým uživatelem.

Základy ověřování

CookieOvěřování na základě je oblíbenou formou ověřování. Systémy ověřování založené na tokenech jsou stále oblíbenější, zejména pro jednostráňové aplikace (SPA).

Když se uživatel ověří pomocí uživatelského jména a hesla, vydá token obsahující ověřovací lístek. Token lze použít k ověřování a autorizaci. Token se uloží jako cookie odesílaný s každým požadavkem, který klient provede. Tento kód se generuje a ověřuje cookie pomocí middlewaru Cookie ověřování. Middleware serializuje objekt zabezpečení uživatele do zašifrovaného cookie. V následných požadavcích middleware ověří cookieobjekt zabezpečení , znovu vytvoří objekt zabezpečení a přiřadí objekt zabezpečení k HttpContext.User vlastnosti.

Ověřování na základě tokenů

Když se uživatel ověří, vystavil token (ne antiforgery token). Token obsahuje informace o uživateli ve formě deklarací identity nebo referenčního tokenu, který odkazuje aplikaci na stav uživatele udržovaný v aplikaci. Když se uživatel pokusí získat přístup k prostředku, který vyžaduje ověření, token se odešle do aplikace s extra autorizační hlavičkou ve formě nosného tokenu. Díky tomuto přístupu je aplikace bezstavová. V každém dalším požadavku se token předá v požadavku na ověření na straně serveru. Tento token není šifrovaný, je zakódovaný. Na serveru je token dekódován pro přístup k jeho informacím. Pokud chcete token odeslat při dalších požadavcích, uložte ho do místního úložiště prohlížeče. Umístění tokenu do místního úložiště prohlížeče a jeho načtení a jeho použití jako nosný token poskytuje ochranu před útoky CSRF. Pokud je však aplikace zranitelná vůči injektáži skriptu prostřednictvím XSS nebo ohroženého externího javascriptového souboru, útočník by mohl načíst libovolnou hodnotu z místního úložiště a odeslat ji sobě. ASP.NET Core ve výchozím nastavení kóduje veškerý výstup na straně serveru z proměnných a snižuje riziko XSS. Pokud toto chování přepíšete pomocí Html.Raw nebo vlastního kódu s nedůvěryhodným vstupem, můžete zvýšit riziko XSS.

Nedělejte si starosti s ohrožením zabezpečení CSRF, pokud je token uložený v místním úložišti prohlížeče. CSRF je problém, když je token uložen v .cookie Další informace najdete v ukázce kódu SPA problému GitHubu se dvěma cookiekódy.

Více aplikací hostovaných v jedné doméně

Sdílená hostitelské prostředí jsou zranitelná vůči napadení relace, přihlášení CSRF a dalším útokům.

I když example1.contoso.net a example2.contoso.net jsou různí hostitelé, existuje implicitní vztah důvěryhodnosti mezi hostiteli v rámci *.contoso.net domény. Tento implicitní vztah důvěryhodnosti umožňuje potenciálně nedůvěryhodným hostitelům ovlivnit vzájemné cookievztahy (zásady stejného původu, které řídí požadavky AJAX, nemusí nutně platit pro http cookies).

Útoky, které využívají důvěryhodné cookieservery mezi aplikacemi hostovanými ve stejné doméně, můžou být znemožněné tím, že nesdílí domény. Když je každá aplikace hostovaná ve vlastní doméně, neexistuje žádný implicitní cookie vztah důvěryhodnosti, který by bylo potřeba zneužít.

Antiforgery v ASP.NET Core

Upozorňující

ASP.NET Core implementuje antiforgery pomocí ASP.NET Core Data Protection. Zásobník ochrany dat musí být nakonfigurovaný tak, aby fungoval v serverové farmě. Další informace najdete v tématu Konfigurace ochrany dat.

Do kontejneru injektáže závislostí se přidá middleware antiforgery, když je volána Program.csněkterá z následujících rozhraní API:

Další informace naleznete v tématu Antiforgery s minimálními rozhraními API.

Obslužná rutina značky form vkládá do elementů formulářů HTML tokeny proti padělkům. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:

<form method="post">
    <!-- ... -->
</form>

Podobně generuje IHtmlHelper.BeginForm antiforgery tokeny ve výchozím nastavení, pokud metoda formuláře není GET.

Automatické generování tokenů antiforgery pro elementy formuláře HTML nastane, když <form> značka obsahuje method="post" atribut a některé z následujících hodnot jsou pravdivé:

  • Atribut akce je prázdný (action="").
  • Atribut akce není zadán (<form method="post">).

Automatické generování antiforgerických tokenů pro elementy formuláře HTML lze zakázat:

  • Explicitně zakažte antiforgery tokeny s atributem asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Prvek formuláře je odhlasován od pomocných rutin značek pomocí symbolu odhlásit se:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Odeberte zobrazení FormTagHelper . Ze FormTagHelper zobrazení lze odebrat přidáním následující direktivy Razor do zobrazení:

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Poznámka:

Razor Stránky jsou automaticky chráněny před XSRF/CSRF. Další informace najdete v tématu XSRF/CSRF a Razor Pages.

Nejběžnějším přístupem k ochraně před útoky CSRF je použití vzoru tokenů synchronizátoru (STP). STP se používá, když uživatel požádá o stránku s daty formuláře:

  1. Server odešle klientovi token přidružený k identitě aktuálního uživatele.
  2. Klient odešle token zpět na server k ověření.
  3. Pokud server obdrží token, který neodpovídá identitě ověřeného uživatele, žádost se odmítne.

Token je jedinečný a nepředvídatelný. Token lze použít také k zajištění správného sekvencování řady požadavků (například k zajištění pořadí požadavků na stránce 1 > strana 2 > strana 3). Všechny formuláře v šablonách ASP.NET Core MVC a Razor Pages generují antiforgery tokeny. Následující dvojice příkladů zobrazení generuje antiforgery tokeny:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Explicitně přidejte do elementu antiforgery token <form> bez použití pomocných rutin značek s pomocným rutinou @Html.AntiForgeryTokenHTML:

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

V každém z předchozích případů ASP.NET Core přidá skryté pole formuláře podobné následujícímu příkladu:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core obsahuje tři filtry pro práci s antiforgery tokeny:

Antiforgery s AddControllers

Volání AddControllers nepovoluje antiforgery tokeny. AddControllersWithViews musí být volána, aby byla podporována integrovaná antiforgery token.

Více karet prohlížeče a vzor tokenu synchronizátoru

Se vzorem tokenu synchronizátoru obsahuje pouze naposledy načtená stránka platný antiforgery token. Použití více karet může být problematické. Pokud například uživatel otevře více karet:

  • Pouze naposledy načtená karta obsahuje platný antiforgery token.
  • Požadavky provedené z dříve načtených karet selžou s chybou: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Pokud se jedná o problém, zvažte alternativní vzory ochrany CSRF.

Konfigurace antiforgery pomocí AntiforgeryOptions

Přizpůsobit AntiforgeryOptions v Program.cs:

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Nastavte antiforgery Cookie vlastnosti pomocí vlastností CookieBuilder třídy, jak je znázorněno v následující tabulce.

Možnost Popis
Cookie Určuje nastavení použitá k vytvoření antiforgery cookies.
FormFieldName Název skrytého pole formuláře používaného systémem antiforgery k vykreslení tokenů antiforgery v zobrazeních.
HeaderName Název hlavičky používané systémem antiforgery. Pokud nullsystém považuje pouze data formuláře.
SuppressXFrameOptionsHeader Určuje, jestli se má potlačit generování hlavičky X-Frame-Options . Ve výchozím nastavení se hlavička vygeneruje s hodnotou SAMEORIGIN. Výchozí hodnota falseje .

Další informace najdete na webu CookieAuthenticationOptions.

Generování antiforgery tokenů pomocí IAntiforgery

IAntiforgery poskytuje rozhraní API ke konfiguraci antiforgery funkcí. IAntiforgery lze požádat o Program.cs použití WebApplication.Services. Následující příklad používá middleware z domovské stránky aplikace k vygenerování antiforgery token a jeho odeslání v odpovědi jako cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

Předchozí příklad nastaví pojmenovanou cookieXSRF-TOKEN. Klient si to cookie může přečíst a zadat jeho hodnotu jako hlavičku připojenou k žádostem AJAX. Angular například obsahuje integrovanou ochranu XSRF, která ve výchozím nastavení čte pojmenovanou XSRF-TOKENcookie.

Vyžadovat ověření antiforgery

Filtr akcí ValidateAntiForgeryToken lze použít u jednotlivé akce, kontroleru nebo globálně. Požadavky provedené na akce, které mají tento filtr použitý, jsou blokované, pokud požadavek neobsahuje platný antiforgery token:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

Atribut ValidateAntiForgeryToken vyžaduje token pro požadavky na metody akce, které označí, včetně požadavků HTTP GET. ValidateAntiForgeryToken Pokud se atribut použije na kontrolery aplikace, můžete ho přepsat pomocí atributuIgnoreAntiforgeryToken.

Automatické ověření tokenů antiforgery pouze pro nebezpečné metody HTTP

Místo široce použitého atributu ValidateAntiForgeryToken a jeho přepsání pomocí IgnoreAntiforgeryToken atributů lze použít atribut AutoValidateAntiforgeryToken . Tento atribut funguje stejně jako ValidateAntiForgeryToken atribut s tím rozdílem, že nevyžaduje tokeny pro požadavky provedené pomocí následujících metod HTTP:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Pro scénáře, které nepoužívají rozhraní API, doporučujeme používat AutoValidateAntiforgeryToken široce. Tento atribut zajišťuje, že akce POST jsou ve výchozím nastavení chráněné. Alternativou je ignorovat antiforgery tokeny ve výchozím nastavení, pokud ValidateAntiForgeryToken není použita u jednotlivých metod akcí. V tomto scénáři je pravděpodobnější, že metoda akce POST zůstane nechráněná omylem, takže aplikace bude zranitelná vůči útokům CSRF. Všechny poST by měly odeslat antiforgery token.

Rozhraní API nemají automatický mechanismus pro odesílání jinécookie části tokenu. Implementace pravděpodobně závisí na implementaci klientského kódu. Tady je několik příkladů:

Příklad na úrovni třídy:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Globální příklad:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Přepsání atributů antiforgery globálního serveru nebo kontroleru

Filtr IgnoreAntiforgeryToken se používá k odstranění potřeby tokenu antiforgery pro danou akci (nebo kontroler). Při použití tento filtr přepíše a AutoValidateAntiforgeryToken filtry ValidateAntiForgeryToken zadané na vyšší úrovni (globálně nebo v kontroleru).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Aktualizace tokenů po ověření

Tokeny by se měly aktualizovat po ověření uživatele přesměrováním uživatele na stránku zobrazení nebo Razor stránky.

JavaScript, AJAX a SPA

V tradičních aplikacích založených na HTML se antiforgery tokeny předávají serveru pomocí skrytých polí formuláře. V moderních aplikacích založených na JavaScriptu a SA se mnoho požadavků provádí programově. Tyto požadavky AJAX mohou k odeslání tokenu použít jiné techniky, jako jsou hlavičky požadavků nebo cookiehlavičky.

Pokud cookiese používají k ukládání ověřovacích tokenů a k ověřování požadavků rozhraní API na serveru, je CSRF potenciálním problémem. Pokud se k uložení tokenu používá místní úložiště, může se zmírnit ohrožení zabezpečení CSRF, protože hodnoty z místního úložiště se na server neodesílají automaticky s každou žádostí. Použití místního úložiště k uložení antiforgery tokenu na klientovi a odeslání tokenu jako hlavičky požadavku je doporučený postup.

Blazor

Další informace najdete v tématu ASP.NET ověřování a autorizace jádraBlazor.

JavaScript

Pomocí JavaScriptu se zobrazeními lze token vytvořit pomocí služby v zobrazení. IAntiforgery Vložte službu do zobrazení a zavolejteGetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

Předchozí příklad používá JavaScript ke čtení skryté hodnoty pole hlavičky AJAX POST.

Tento přístup eliminuje potřebu přímo řešit nastavení cookieze serveru nebo je číst z klienta. Pokud však vložení IAntiforgery služby není možné, použijte JavaScript pro přístup k tokenům v cookies:

  • Přístupové tokeny v dalším požadavku na server, obvykle same-origin.
  • cookiePomocí obsahu vytvořte hlavičku s hodnotou tokenu.

Za předpokladu, že skript odešle token v hlavičce požadavku s názvem X-XSRF-TOKEN, nakonfigurujte službu antiforgery tak, aby hledala hlavičku X-XSRF-TOKEN :

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

Následující příklad přidá chráněný koncový bod, který zapíše token požadavku do javascriptově čitelného cookiekódu:

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

Následující příklad používá JavaScript k vytvoření požadavku AJAX na získání tokenu a provedení dalšího požadavku s příslušnou hlavičkou:

var response = await fetch("/antiforgery/token", {
    method: "GET",
    headers: { "Authorization": authorizationToken }
});

if (response.ok) {
    // https://developer.mozilla.org/docs/web/api/document/cookie
    const xsrfToken = document.cookie
        .split("; ")
        .find(row => row.startsWith("XSRF-TOKEN="))
        .split("=")[1];

    response = await fetch("/JavaScript/FetchEndpoint", {
        method: "POST",
        headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
    });

    if (response.ok) {
        resultElement.innerText = await response.text();
    } else {
        resultElement.innerText = `Request Failed: ${response.status}`
    }
} else {    
    resultElement.innerText = `Request Failed: ${response.status}`
}

Poznámka:

Pokud je token antiforgery zadaný v hlavičce požadavku i v datové části formuláře, ověří se pouze token v hlavičce.

Antiforgery s minimálními rozhraními API

Zavolejte AddAntiforgery a UseAntiforgery(IApplicationBuilder) zaregistrujte antiforgery služby v DI. Antiforgery tokeny se používají ke zmírnění útoků proti padělání požadavků mezi weby.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/", () => "Hello World!");

app.Run();

Antiforgery middleware:

Antiforgery token je ověřen pouze v případě, že:

  • Koncový bod obsahuje metadata implementuje IAntiforgeryMetadata where RequiresValidation=true.
  • Metoda HTTP přidružená ke koncovému bodu je relevantní metoda HTTP. Relevantní metody jsou všechny metody HTTP s výjimkou TRASOVÁNÍ , OPTIONS, HEAD a GET.
  • Požadavek je přidružený k platnému koncovému bodu.

Poznámka: Pokud je tento příkaz povolen ručně, musí se middleware antiforgery spustit po ověření a autorizačním middlewaru, aby se zabránilo čtení dat formuláře, když je uživatel neověřený.

Ve výchozím nastavení vyžadují minimální rozhraní API, která přijímají data formuláře, ověření antiforgery tokenu.

Zvažte následující GenerateForm metodu:

public static string GenerateForm(string action, 
    AntiforgeryTokenSet token, bool UseToken=true)
{
    string tokenInput = "";
    if (UseToken)
    {
        tokenInput = $@"<input name=""{token.FormFieldName}""
                         type=""hidden"" value=""{token.RequestToken}"" />";
    }

    return $@"
    <html><body>
        <form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
            {tokenInput}
            <input type=""text"" name=""name"" />
            <input type=""date"" name=""dueDate"" />
            <input type=""checkbox"" name=""isCompleted"" />
            <input type=""submit"" />
        </form>
    </body></html>
";
}

Předchozí kód obsahuje tři argumenty, akci, token proti padělání a bool indikující, jestli se má token použít.

Podívejte se na následující ukázku:

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

// Pass token
app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) =>
{
    var token = antiforgery.GetAndStoreTokens(context);
    return Results.Content(MyHtml.GenerateForm("/todo", token), "text/html");
});

// Don't pass a token, fails
app.MapGet("/SkipToken", (HttpContext context, IAntiforgery antiforgery) =>
{
    var token = antiforgery.GetAndStoreTokens(context);
    return Results.Content(MyHtml.GenerateForm("/todo",token, false ), "text/html");
});

// Post to /todo2. DisableAntiforgery on that endpoint so no token needed.
app.MapGet("/DisableAntiforgery", (HttpContext context, IAntiforgery antiforgery) =>
{
    var token = antiforgery.GetAndStoreTokens(context);
    return Results.Content(MyHtml.GenerateForm("/todo2", token, false), "text/html");
});

app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
                                                .DisableAntiforgery();

app.Run();

class Todo
{
    public required string Name { get; set; }
    public bool IsCompleted { get; set; }
    public DateTime DueDate { get; set; }
}

public static class MyHtml
{
    public static string GenerateForm(string action, 
        AntiforgeryTokenSet token, bool UseToken=true)
    {
        string tokenInput = "";
        if (UseToken)
        {
            tokenInput = $@"<input name=""{token.FormFieldName}""
                             type=""hidden"" value=""{token.RequestToken}"" />";
        }

        return $@"
        <html><body>
            <form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
                {tokenInput}
                <input type=""text"" name=""name"" />
                <input type=""date"" name=""dueDate"" />
                <input type=""checkbox"" name=""isCompleted"" />
                <input type=""submit"" />
            </form>
        </body></html>
    ";
    }
}

V předchozím kódu publikuje příspěvky do:

  • /todo vyžaduje platný antiforgery token.
  • /todo2nevyžaduje platný antiforgery token, protože DisableAntiforgery je volána.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
                                                .DisableAntiforgery();

A POST to:

  • /todo z formuláře vygenerovaného / koncovým bodem bude úspěšný, protože token antiforgery je platný.
  • /todo z formuláře generovaného /SkipToken chybou, protože antiforgery není zahrnuta.
  • /todo2 z formuláře vygenerovaného /DisableAntiforgery koncovým bodem proběhne úspěšně, protože antiforgery není vyžadováno.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
                                                .DisableAntiforgery();

Při odeslání formuláře bez platného antiforgery tokenu:

  • Ve vývojovém prostředí se vyvolá výjimka.
  • V produkčním prostředí se zaprotokoluje zpráva.

Ověřování systému Windows a antiforgery cookies

Při použití ověřování systému Windows musí být koncové body aplikací chráněné proti útokům CSRF stejným způsobem jako u útoků.cookie Prohlížeč implicitně odesílá kontext ověřování na server a koncové body, které musí být chráněné před útoky CSRF.

Rozšířit antiforgery

Tento IAntiforgeryAdditionalDataProvider typ umožňuje vývojářům rozšířit chování systému anti-CSRF tím, že v každém tokenu přetáhne další data. Metoda GetAdditionalData se volá při každém vygenerování tokenu pole a návratová hodnota se vloží do vygenerovaného tokenu. Implementátor by mohl vrátit časové razítko, nece nebo jinou hodnotu a potom volat ValidateAdditionalData ověření těchto dat při ověření tokenu. Uživatelské jméno klienta je již vloženo do vygenerovaných tokenů, takže tyto informace nemusíte obsahovat. Pokud token obsahuje doplňková data, ale není nakonfigurovaná žádná IAntiForgeryAdditionalDataProvider , doplňková data se neověřují.

Další materiály

Padělání požadavků mezi weby (označované také jako XSRF nebo CSRF) je útok na aplikace hostované na webu, kdy škodlivá webová aplikace může ovlivnit interakci mezi klientským prohlížečem a webovou aplikací, která důvěřuje danému prohlížeči. Tyto útoky jsou možné, protože webové prohlížeče automaticky odesílají některé typy ověřovacích tokenů s každou žádostí na web. Tato forma zneužití se také označuje jako útok jedním kliknutím nebo jízda na relaci, protože útok využívá dříve ověřenou relaci uživatele.

Příklad útoku CSRF:

  1. Uživatel se www.good-banking-site.example.com přihlásí pomocí ověřování pomocí formulářů. Server ověřuje uživatele a vydává odpověď, která zahrnuje ověřování cookie. Web je zranitelný vůči útoku, protože důvěřuje všem požadavkem, který obdrží s platným ověřováním cookie.

  2. Uživatel navštíví škodlivý web. www.bad-crook-site.example.com

    Škodlivý web obsahuje www.bad-crook-site.example.comformulář HTML podobný následujícímu příkladu:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Všimněte si, že příspěvky formuláře action na ohrožený web, ne na škodlivý web. Toto je "cross-site" část CSRF.

  3. Uživatel vybere tlačítko Odeslat. Prohlížeč vytvoří požadavek a automaticky zahrne ověřování cookie pro požadovanou doménu. www.good-banking-site.example.com

  4. Požadavek se spustí na www.good-banking-site.example.com serveru s kontextem ověřování uživatele a může provést jakoukoli akci, kterou může ověřený uživatel provést.

Kromě scénáře, ve kterém uživatel vybere tlačítko pro odeslání formuláře, může škodlivý web:

  • Spusťte skript, který automaticky odešle formulář.
  • Odešlete formulář jako požadavek AJAX.
  • Skryjte formulář pomocí šablon stylů CSS.

Tyto alternativní scénáře nevyžadují žádnou akci ani vstup od jiného uživatele, než je počáteční návštěva škodlivého webu.

Použití PROTOKOLU HTTPS nezabrání útoku CSRF. Škodlivý web může požadavek odeslat https://www.good-banking-site.com/ stejně snadno, jako by mohl odeslat nezabezpečený požadavek.

Některé cílové koncové body útoků, které reagují na požadavky GET, v takovém případě je možné k provedení akce použít značku image. Tato forma útoku je běžná na webech fóra, které umožňují obrázky, ale blokují JavaScript. Aplikace, které mění stav požadavků GET, kde se mění proměnné nebo prostředky, jsou zranitelné vůči škodlivým útokům. Požadavky GET, které změní stav, jsou nezabezpečené. Osvědčeným postupem je nikdy změnit stav požadavku GET.

Útoky CSRF jsou možné vůči webovým aplikacím, které používají cookieověřování, protože:

  • cookieÚložiště prohlížečů vydané webovou aplikací
  • Uložené cookierelace cookiezahrnutí pro ověřené uživatele.
  • Prohlížeče odesílají všechny soubory cookiepřidružené k doméně do webové aplikace bez ohledu na to, jak se požadavek na aplikaci vygeneroval v prohlížeči.

Útoky CSRF se ale neomezují pouze na zneužití cookie. Například základní ověřování a ověřování hodnotou hash je také ohroženo. Jakmile se uživatel přihlásí pomocí ověřování Basic nebo Digest, prohlížeč automaticky odešle přihlašovací údaje, dokud relace nedokončí.

V tomto kontextu relace odkazuje na relaci na straně klienta, během které je uživatel ověřen. Nesouvisí s relacemi na straně serveru nebo se ASP.NET Middleware základní relace.

Uživatelé mohou chránit před ohroženími zabezpečení CSRF tím, že podniknou opatření:

  • Po dokončení se odhlaste z webových aplikací.
  • Pravidelně vymažte prohlížeč cookie.

Ohrožení zabezpečení CSRF jsou ale v zásadě problém s webovou aplikací, nikoli koncovým uživatelem.

Základy ověřování

CookieOvěřování na základě je oblíbenou formou ověřování. Systémy ověřování založené na tokenech jsou stále oblíbenější, zejména pro jednostráňové aplikace (SPA).

Když se uživatel ověří pomocí uživatelského jména a hesla, vydá token obsahující ověřovací lístek, který se dá použít k ověřování a autorizaci. Token se uloží jako cookie odesílaný s každým požadavkem, který klient provede. Tento kód generuje Cookie a ověřuje cookie middleware ověřování. Middleware serializuje objekt zabezpečení uživatele do zašifrovaného cookie. V následných požadavcích middleware ověří cookieobjekt zabezpečení , znovu vytvoří objekt zabezpečení a přiřadí objekt zabezpečení k HttpContext.User vlastnosti.

Ověřování na základě tokenů

Když se uživatel ověří, vystavil token (ne antiforgery token). Token obsahuje informace o uživateli ve formě deklarací identity nebo referenčního tokenu, který odkazuje aplikaci na stav uživatele udržovaný v aplikaci. Když se uživatel pokusí získat přístup k prostředku, který vyžaduje ověření, token se odešle do aplikace s extra autorizační hlavičkou ve formě nosného tokenu. Díky tomuto přístupu je aplikace bezstavová. V každém dalším požadavku se token předá v požadavku na ověření na straně serveru. Tento token není šifrovaný, je zakódovaný. Na serveru je token dekódován pro přístup k jeho informacím. Pokud chcete token odeslat při dalších požadavcích, uložte ho do místního úložiště prohlížeče. Umístění tokenu do místního úložiště prohlížeče a jeho načtení a jeho použití jako nosný token poskytuje ochranu před útoky CSRF. Pokud je však aplikace zranitelná vůči injektáži skriptu prostřednictvím XSS nebo ohroženého externího javascriptového souboru, útočník by mohl načíst libovolnou hodnotu z místního úložiště a odeslat ji sobě. ASP.NET Core ve výchozím nastavení kóduje veškerý výstup na straně serveru z proměnných a snižuje riziko XSS. Pokud toto chování přepíšete pomocí Html.Raw nebo vlastního kódu s nedůvěryhodným vstupem, můžete zvýšit riziko XSS.

Nedělejte si starosti s ohrožením zabezpečení CSRF, pokud je token uložený v místním úložišti prohlížeče. CSRF je problém, když je token uložen v .cookie Další informace najdete v ukázce kódu SPA problému GitHubu se dvěma cookiekódy.

Více aplikací hostovaných v jedné doméně

Sdílená hostitelské prostředí jsou zranitelná vůči napadení relace, přihlášení CSRF a dalším útokům.

I když example1.contoso.net a example2.contoso.net jsou různí hostitelé, existuje implicitní vztah důvěryhodnosti mezi hostiteli v rámci *.contoso.net domény. Tento implicitní vztah důvěryhodnosti umožňuje potenciálně nedůvěryhodným hostitelům ovlivnit vzájemné cookievztahy (zásady stejného původu, které řídí požadavky AJAX, nemusí nutně platit pro http cookies).

Útoky, které využívají důvěryhodné cookieservery mezi aplikacemi hostovanými ve stejné doméně, můžou být znemožněné tím, že nesdílí domény. Když je každá aplikace hostovaná ve vlastní doméně, neexistuje žádný implicitní cookie vztah důvěryhodnosti, který by bylo potřeba zneužít.

Antiforgery v ASP.NET Core

Upozorňující

ASP.NET Core implementuje antiforgery pomocí ASP.NET Core Data Protection. Zásobník ochrany dat musí být nakonfigurovaný tak, aby fungoval v serverové farmě. Další informace najdete v tématu Konfigurace ochrany dat.

Do kontejneru injektáže závislostí se přidá middleware antiforgery, když je volána Program.csněkterá z následujících rozhraní API:

Obslužná rutina značky form vkládá do elementů formulářů HTML tokeny proti padělkům. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:

<form method="post">
    <!-- ... -->
</form>

Podobně generuje IHtmlHelper.BeginForm antiforgery tokeny ve výchozím nastavení, pokud metoda formuláře není GET.

Automatické generování tokenů antiforgery pro elementy formuláře HTML nastane, když <form> značka obsahuje method="post" atribut a některé z následujících hodnot jsou pravdivé:

  • Atribut akce je prázdný (action="").
  • Atribut akce není zadán (<form method="post">).

Automatické generování antiforgerických tokenů pro elementy formuláře HTML lze zakázat:

  • Explicitně zakažte antiforgery tokeny s atributem asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Prvek formuláře je odhlasován od pomocných rutin značek pomocí symbolu odhlásit se:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Odeberte zobrazení FormTagHelper . Ze FormTagHelper zobrazení lze odebrat přidáním následující direktivy Razor do zobrazení:

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Poznámka:

Razor Stránky jsou automaticky chráněny před XSRF/CSRF. Další informace najdete v tématu XSRF/CSRF a Razor Pages.

Nejběžnějším přístupem k ochraně před útoky CSRF je použití vzoru tokenů synchronizátoru (STP). STP se používá, když uživatel požádá o stránku s daty formuláře:

  1. Server odešle klientovi token přidružený k identitě aktuálního uživatele.
  2. Klient odešle token zpět na server k ověření.
  3. Pokud server obdrží token, který neodpovídá identitě ověřeného uživatele, žádost se odmítne.

Token je jedinečný a nepředvídatelný. Token lze použít také k zajištění správného sekvencování řady požadavků (například k zajištění pořadí požadavků na stránce 1 > strana 2 > strana 3). Všechny formuláře v šablonách ASP.NET Core MVC a Razor Pages generují antiforgery tokeny. Následující dvojice příkladů zobrazení generuje antiforgery tokeny:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Explicitně přidejte do elementu antiforgery token <form> bez použití pomocných rutin značek s pomocným rutinou @Html.AntiForgeryTokenHTML:

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

V každém z předchozích případů ASP.NET Core přidá skryté pole formuláře podobné následujícímu příkladu:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core obsahuje tři filtry pro práci s antiforgery tokeny:

Antiforgery s AddControllers

Volání AddControllers nepovoluje antiforgery tokeny. AddControllersWithViews musí být volána, aby byla podporována integrovaná antiforgery token.

Více karet prohlížeče a vzor tokenu synchronizátoru

Se vzorem tokenu synchronizátoru obsahuje pouze naposledy načtená stránka platný antiforgery token. Použití více karet může být problematické. Pokud například uživatel otevře více karet:

  • Pouze naposledy načtená karta obsahuje platný antiforgery token.
  • Požadavky provedené z dříve načtených karet selžou s chybou: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Pokud se jedná o problém, zvažte alternativní vzory ochrany CSRF.

Konfigurace antiforgery pomocí AntiforgeryOptions

Přizpůsobit AntiforgeryOptions v Program.cs:

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Nastavte antiforgery Cookie vlastnosti pomocí vlastností CookieBuilder třídy, jak je znázorněno v následující tabulce.

Možnost Popis
Cookie Určuje nastavení použitá k vytvoření antiforgery cookies.
FormFieldName Název skrytého pole formuláře používaného systémem antiforgery k vykreslení tokenů antiforgery v zobrazeních.
HeaderName Název hlavičky používané systémem antiforgery. Pokud nullsystém považuje pouze data formuláře.
SuppressXFrameOptionsHeader Určuje, jestli se má potlačit generování hlavičky X-Frame-Options . Ve výchozím nastavení se hlavička vygeneruje s hodnotou SAMEORIGIN. Výchozí hodnota falseje .

Další informace najdete na webu CookieAuthenticationOptions.

Generování antiforgery tokenů pomocí IAntiforgery

IAntiforgery poskytuje rozhraní API ke konfiguraci antiforgery funkcí. IAntiforgery lze požádat o Program.cs použití WebApplication.Services. Následující příklad používá middleware z domovské stránky aplikace k vygenerování antiforgery token a jeho odeslání v odpovědi jako cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

Předchozí příklad nastaví pojmenovanou cookieXSRF-TOKEN. Klient si to cookie může přečíst a zadat jeho hodnotu jako hlavičku připojenou k žádostem AJAX. Angular například obsahuje integrovanou ochranu XSRF, která ve výchozím nastavení čte pojmenovanou XSRF-TOKENcookie.

Vyžadovat ověření antiforgery

Filtr akcí ValidateAntiForgeryToken lze použít u jednotlivé akce, kontroleru nebo globálně. Požadavky provedené na akce, které mají tento filtr použitý, jsou blokované, pokud požadavek neobsahuje platný antiforgery token:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

Atribut ValidateAntiForgeryToken vyžaduje token pro požadavky na metody akce, které označí, včetně požadavků HTTP GET. ValidateAntiForgeryToken Pokud se atribut použije na kontrolery aplikace, můžete ho přepsat pomocí atributuIgnoreAntiforgeryToken.

Automatické ověření tokenů antiforgery pouze pro nebezpečné metody HTTP

Místo široce použitého atributu ValidateAntiForgeryToken a jeho přepsání pomocí IgnoreAntiforgeryToken atributů lze použít atribut AutoValidateAntiforgeryToken . Tento atribut funguje stejně jako ValidateAntiForgeryToken atribut s tím rozdílem, že nevyžaduje tokeny pro požadavky provedené pomocí následujících metod HTTP:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Pro scénáře, které nepoužívají rozhraní API, doporučujeme používat AutoValidateAntiforgeryToken široce. Tento atribut zajišťuje, že akce POST jsou ve výchozím nastavení chráněné. Alternativou je ignorovat antiforgery tokeny ve výchozím nastavení, pokud ValidateAntiForgeryToken není použita u jednotlivých metod akcí. V tomto scénáři je pravděpodobnější, že metoda akce POST zůstane nechráněná omylem, takže aplikace bude zranitelná vůči útokům CSRF. Všechny poST by měly odeslat antiforgery token.

Rozhraní API nemají automatický mechanismus pro odesílání jinécookie části tokenu. Implementace pravděpodobně závisí na implementaci klientského kódu. Tady je několik příkladů:

Příklad na úrovni třídy:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Globální příklad:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Přepsání atributů antiforgery globálního serveru nebo kontroleru

Filtr IgnoreAntiforgeryToken se používá k odstranění potřeby tokenu antiforgery pro danou akci (nebo kontroler). Při použití tento filtr přepíše a AutoValidateAntiforgeryToken filtry ValidateAntiForgeryToken zadané na vyšší úrovni (globálně nebo v kontroleru).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Aktualizace tokenů po ověření

Tokeny by se měly aktualizovat po ověření uživatele přesměrováním uživatele na stránku zobrazení nebo Razor stránky.

JavaScript, AJAX a SPA

V tradičních aplikacích založených na HTML se antiforgery tokeny předávají serveru pomocí skrytých polí formuláře. V moderních aplikacích založených na JavaScriptu a SA se mnoho požadavků provádí programově. Tyto požadavky AJAX můžou k odeslání tokenu použít jiné techniky (například hlavičky požadavků nebo cookies).

Pokud cookiese používají k ukládání ověřovacích tokenů a k ověřování požadavků rozhraní API na serveru, je CSRF potenciálním problémem. Pokud se k uložení tokenu používá místní úložiště, může se zmírnit ohrožení zabezpečení CSRF, protože hodnoty z místního úložiště se na server neodesílají automaticky s každou žádostí. Použití místního úložiště k uložení antiforgery tokenu na klientovi a odeslání tokenu jako hlavičky požadavku je doporučený postup.

JavaScript

Pomocí JavaScriptu se zobrazeními lze token vytvořit pomocí služby v zobrazení. IAntiforgery Vložte službu do zobrazení a zavolejteGetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

Předchozí příklad používá JavaScript ke čtení skryté hodnoty pole hlavičky AJAX POST.

Tento přístup eliminuje potřebu přímo řešit nastavení cookieze serveru nebo je číst z klienta. Pokud však vložení IAntiforgery služby není možné, použijte JavaScript pro přístup k tokenům v cookies:

  • Přístupové tokeny v dalším požadavku na server, obvykle same-origin.
  • cookiePomocí obsahu vytvořte hlavičku s hodnotou tokenu.

Za předpokladu, že skript odešle token v hlavičce požadavku s názvem X-XSRF-TOKEN, nakonfigurujte službu antiforgery tak, aby hledala hlavičku X-XSRF-TOKEN :

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

Následující příklad přidá chráněný koncový bod, který zapíše token požadavku do javascriptově čitelného cookiekódu:

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

Následující příklad používá JavaScript k vytvoření požadavku AJAX na získání tokenu a provedení dalšího požadavku s příslušnou hlavičkou:

var response = await fetch("/antiforgery/token", {
    method: "GET",
    headers: { "Authorization": authorizationToken }
});

if (response.ok) {
    // https://developer.mozilla.org/docs/web/api/document/cookie
    const xsrfToken = document.cookie
        .split("; ")
        .find(row => row.startsWith("XSRF-TOKEN="))
        .split("=")[1];

    response = await fetch("/JavaScript/FetchEndpoint", {
        method: "POST",
        headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
    });

    if (response.ok) {
        resultElement.innerText = await response.text();
    } else {
        resultElement.innerText = `Request Failed: ${response.status}`
    }
} else {    
    resultElement.innerText = `Request Failed: ${response.status}`
}

Poznámka:

Pokud je token antiforgery zadaný v hlavičce požadavku i v datové části formuláře, ověří se pouze token v hlavičce.

Antiforgery s minimálními rozhraními API

Minimal APIsnepodporuje použití zahrnutých filtrů (ValidateAntiForgeryTokenAutoValidateAntiforgeryToken, , IgnoreAntiforgeryToken), IAntiforgery ale poskytuje požadovaná rozhraní API k ověření požadavku.

Následující příklad vytvoří filtr, který ověří token antiforgery:

internal static class AntiForgeryExtensions
{
    public static TBuilder ValidateAntiforgery<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
    {
        return builder.AddEndpointFilter(routeHandlerFilter: async (context, next) =>
        {
            try
            {
                var antiForgeryService = context.HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
                await antiForgeryService.ValidateRequestAsync(context.HttpContext);
            }
            catch (AntiforgeryValidationException)
            {
                return Results.BadRequest("Antiforgery token validation failed.");
            }

            return await next(context);

        });
    }
}

Filtr se pak dá použít na koncový bod:

app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
    .RequireAuthorization()
    .ValidateAntiforgery();

Ověřování systému Windows a antiforgery cookies

Při použití ověřování systému Windows musí být koncové body aplikací chráněné proti útokům CSRF stejným způsobem jako u útoků.cookie Prohlížeč implicitně odesílá kontext ověřování na server a koncové body, které musí být chráněné před útoky CSRF.

Rozšířit antiforgery

Tento IAntiforgeryAdditionalDataProvider typ umožňuje vývojářům rozšířit chování systému anti-CSRF tím, že v každém tokenu přetáhne další data. Metoda GetAdditionalData se volá při každém vygenerování tokenu pole a návratová hodnota se vloží do vygenerovaného tokenu. Implementátor by mohl vrátit časové razítko, nece nebo jinou hodnotu a potom volat ValidateAdditionalData ověření těchto dat při ověření tokenu. Uživatelské jméno klienta je již vloženo do vygenerovaných tokenů, takže tyto informace nemusíte obsahovat. Pokud token obsahuje doplňková data, ale není nakonfigurovaná žádná IAntiForgeryAdditionalDataProvider , doplňková data se neověřují.

Další materiály

Padělání požadavků mezi weby (označované také jako XSRF nebo CSRF) je útok na aplikace hostované na webu, kdy škodlivá webová aplikace může ovlivnit interakci mezi klientským prohlížečem a webovou aplikací, která důvěřuje danému prohlížeči. Tyto útoky jsou možné, protože webové prohlížeče automaticky odesílají některé typy ověřovacích tokenů s každou žádostí na web. Tato forma zneužití se také označuje jako útok jedním kliknutím nebo jízda na relaci, protože útok využívá dříve ověřenou relaci uživatele.

Příklad útoku CSRF:

  1. Uživatel se www.good-banking-site.example.com přihlásí pomocí ověřování pomocí formulářů. Server ověřuje uživatele a vydává odpověď, která zahrnuje ověřování cookie. Web je zranitelný vůči útoku, protože důvěřuje všem požadavkem, který obdrží s platným ověřováním cookie.

  2. Uživatel navštíví škodlivý web. www.bad-crook-site.example.com

    Škodlivý web obsahuje www.bad-crook-site.example.comformulář HTML podobný následujícímu příkladu:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Všimněte si, že příspěvky formuláře action na ohrožený web, ne na škodlivý web. Toto je "cross-site" část CSRF.

  3. Uživatel vybere tlačítko Odeslat. Prohlížeč vytvoří požadavek a automaticky zahrne ověřování cookie pro požadovanou doménu. www.good-banking-site.example.com

  4. Požadavek se spustí na www.good-banking-site.example.com serveru s kontextem ověřování uživatele a může provést jakoukoli akci, kterou může ověřený uživatel provést.

Kromě scénáře, ve kterém uživatel vybere tlačítko pro odeslání formuláře, může škodlivý web:

  • Spusťte skript, který automaticky odešle formulář.
  • Odešlete formulář jako požadavek AJAX.
  • Skryjte formulář pomocí šablon stylů CSS.

Tyto alternativní scénáře nevyžadují žádnou akci ani vstup od jiného uživatele, než je počáteční návštěva škodlivého webu.

Použití PROTOKOLU HTTPS nezabrání útoku CSRF. Škodlivý web může požadavek odeslat https://www.good-banking-site.com/ stejně snadno, jako by mohl odeslat nezabezpečený požadavek.

Některé cílové koncové body útoků, které reagují na požadavky GET, v takovém případě je možné k provedení akce použít značku image. Tato forma útoku je běžná na webech fóra, které umožňují obrázky, ale blokují JavaScript. Aplikace, které mění stav požadavků GET, kde se mění proměnné nebo prostředky, jsou zranitelné vůči škodlivým útokům. Požadavky GET, které změní stav, jsou nezabezpečené. Osvědčeným postupem je nikdy změnit stav požadavku GET.

Útoky CSRF jsou možné vůči webovým aplikacím, které používají cookieověřování, protože:

  • cookieÚložiště prohlížečů vydané webovou aplikací
  • Uložené cookierelace cookiezahrnutí pro ověřené uživatele.
  • Prohlížeče odesílají všechny soubory cookiepřidružené k doméně do webové aplikace bez ohledu na to, jak se požadavek na aplikaci vygeneroval v prohlížeči.

Útoky CSRF se ale neomezují pouze na zneužití cookie. Například základní ověřování a ověřování hodnotou hash je také ohroženo. Jakmile se uživatel přihlásí pomocí ověřování Basic nebo Digest, prohlížeč automaticky odešle přihlašovací údaje, dokud relace nedokončí.

V tomto kontextu relace odkazuje na relaci na straně klienta, během které je uživatel ověřen. Nesouvisí s relacemi na straně serveru nebo se ASP.NET Middleware základní relace.

Uživatelé mohou chránit před ohroženími zabezpečení CSRF tím, že podniknou opatření:

  • Po dokončení se odhlaste z webových aplikací.
  • Pravidelně vymažte prohlížeč cookie.

Ohrožení zabezpečení CSRF jsou ale v zásadě problém s webovou aplikací, nikoli koncovým uživatelem.

Základy ověřování

CookieOvěřování na základě je oblíbenou formou ověřování. Systémy ověřování založené na tokenech jsou stále oblíbenější, zejména pro jednostráňové aplikace (SPA).

Když se uživatel ověří pomocí uživatelského jména a hesla, vydá token obsahující ověřovací lístek, který se dá použít k ověřování a autorizaci. Token se uloží jako cookie odesílaný s každým požadavkem, který klient provede. Tento kód generuje Cookie a ověřuje cookie middleware ověřování. Middleware serializuje objekt zabezpečení uživatele do zašifrovaného cookie. V následných požadavcích middleware ověří cookieobjekt zabezpečení , znovu vytvoří objekt zabezpečení a přiřadí objekt zabezpečení k HttpContext.User vlastnosti.

Ověřování na základě tokenů

Když se uživatel ověří, vystavil token (ne antiforgery token). Token obsahuje informace o uživateli ve formě deklarací identity nebo referenčního tokenu, který odkazuje aplikaci na stav uživatele udržovaný v aplikaci. Když se uživatel pokusí získat přístup k prostředku, který vyžaduje ověření, token se odešle do aplikace s extra autorizační hlavičkou ve formě nosného tokenu. Díky tomuto přístupu je aplikace bezstavová. V každém dalším požadavku se token předá v požadavku na ověření na straně serveru. Tento token není šifrovaný, je zakódovaný. Na serveru je token dekódován pro přístup k jeho informacím. Pokud chcete token odeslat při dalších požadavcích, uložte ho do místního úložiště prohlížeče. Nedělejte si starosti s ohrožením zabezpečení CSRF, pokud je token uložený v místním úložišti prohlížeče. CSRF je problém, když je token uložen v .cookie Další informace najdete v ukázce kódu SPA problému GitHubu se dvěma cookiekódy.

Více aplikací hostovaných v jedné doméně

Sdílená hostitelské prostředí jsou zranitelná vůči napadení relace, přihlášení CSRF a dalším útokům.

I když example1.contoso.net a example2.contoso.net jsou různí hostitelé, existuje implicitní vztah důvěryhodnosti mezi hostiteli v rámci *.contoso.net domény. Tento implicitní vztah důvěryhodnosti umožňuje potenciálně nedůvěryhodným hostitelům ovlivnit vzájemné cookievztahy (zásady stejného původu, které řídí požadavky AJAX, nemusí nutně platit pro http cookies).

Útoky, které využívají důvěryhodné cookieservery mezi aplikacemi hostovanými ve stejné doméně, můžou být znemožněné tím, že nesdílí domény. Když je každá aplikace hostovaná ve vlastní doméně, neexistuje žádný implicitní cookie vztah důvěryhodnosti, který by bylo potřeba zneužít.

Antiforgery v ASP.NET Core

Upozorňující

ASP.NET Core implementuje antiforgery pomocí ASP.NET Core Data Protection. Zásobník ochrany dat musí být nakonfigurovaný tak, aby fungoval v serverové farmě. Další informace najdete v tématu Konfigurace ochrany dat.

Do kontejneru injektáže závislostí se přidá middleware antiforgery, když je volána Program.csněkterá z následujících rozhraní API:

Obslužná rutina značky form vkládá do elementů formulářů HTML tokeny proti padělkům. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:

<form method="post">
    <!-- ... -->
</form>

Podobně generuje IHtmlHelper.BeginForm antiforgery tokeny ve výchozím nastavení, pokud metoda formuláře není GET.

Automatické generování tokenů antiforgery pro elementy formuláře HTML nastane, když <form> značka obsahuje method="post" atribut a některé z následujících hodnot jsou pravdivé:

  • Atribut akce je prázdný (action="").
  • Atribut akce není zadán (<form method="post">).

Automatické generování antiforgerických tokenů pro elementy formuláře HTML lze zakázat:

  • Explicitně zakažte antiforgery tokeny s atributem asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Prvek formuláře je odhlasován od pomocných rutin značek pomocí symbolu odhlásit se:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Odeberte zobrazení FormTagHelper . Ze FormTagHelper zobrazení lze odebrat přidáním následující direktivy Razor do zobrazení:

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Poznámka:

Razor Stránky jsou automaticky chráněny před XSRF/CSRF. Další informace najdete v tématu XSRF/CSRF a Razor Pages.

Nejběžnějším přístupem k ochraně před útoky CSRF je použití vzoru tokenů synchronizátoru (STP). STP se používá, když uživatel požádá o stránku s daty formuláře:

  1. Server odešle klientovi token přidružený k identitě aktuálního uživatele.
  2. Klient odešle token zpět na server k ověření.
  3. Pokud server obdrží token, který neodpovídá identitě ověřeného uživatele, žádost se odmítne.

Token je jedinečný a nepředvídatelný. Token lze použít také k zajištění správného sekvencování řady požadavků (například k zajištění pořadí požadavků na stránce 1 > strana 2 > strana 3). Všechny formuláře v šablonách ASP.NET Core MVC a Razor Pages generují antiforgery tokeny. Následující dvojice příkladů zobrazení generuje antiforgery tokeny:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Explicitně přidejte do elementu antiforgery token <form> bez použití pomocných rutin značek s pomocným rutinou @Html.AntiForgeryTokenHTML:

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

V každém z předchozích případů ASP.NET Core přidá skryté pole formuláře podobné následujícímu příkladu:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core obsahuje tři filtry pro práci s antiforgery tokeny:

Antiforgery s AddControllers

Volání AddControllers nepovoluje antiforgery tokeny. AddControllersWithViews musí být volána, aby byla podporována integrovaná antiforgery token.

Více karet prohlížeče a vzor tokenu synchronizátoru

Se vzorem tokenu synchronizátoru obsahuje pouze naposledy načtená stránka platný antiforgery token. Použití více karet může být problematické. Pokud například uživatel otevře více karet:

  • Pouze naposledy načtená karta obsahuje platný antiforgery token.
  • Požadavky provedené z dříve načtených karet selžou s chybou: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Pokud se jedná o problém, zvažte alternativní vzory ochrany CSRF.

Konfigurace antiforgery pomocí AntiforgeryOptions

Přizpůsobit AntiforgeryOptions v Program.cs:

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Nastavte antiforgery Cookie vlastnosti pomocí vlastností CookieBuilder třídy, jak je znázorněno v následující tabulce.

Možnost Popis
Cookie Určuje nastavení použitá k vytvoření antiforgery cookies.
FormFieldName Název skrytého pole formuláře používaného systémem antiforgery k vykreslení tokenů antiforgery v zobrazeních.
HeaderName Název hlavičky používané systémem antiforgery. Pokud nullsystém považuje pouze data formuláře.
SuppressXFrameOptionsHeader Určuje, jestli se má potlačit generování hlavičky X-Frame-Options . Ve výchozím nastavení se hlavička vygeneruje s hodnotou SAMEORIGIN. Výchozí hodnota falseje .

Další informace najdete na webu CookieAuthenticationOptions.

Generování antiforgery tokenů pomocí IAntiforgery

IAntiforgery poskytuje rozhraní API ke konfiguraci antiforgery funkcí. IAntiforgery lze požádat o Program.cs použití WebApplication.Services. Následující příklad používá middleware z domovské stránky aplikace k vygenerování antiforgery token a jeho odeslání v odpovědi jako cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

Předchozí příklad nastaví pojmenovanou cookieXSRF-TOKEN. Klient si to cookie může přečíst a zadat jeho hodnotu jako hlavičku připojenou k žádostem AJAX. Angular například obsahuje integrovanou ochranu XSRF, která ve výchozím nastavení čte pojmenovanou XSRF-TOKENcookie.

Vyžadovat ověření antiforgery

Filtr akcí ValidateAntiForgeryToken lze použít u jednotlivé akce, kontroleru nebo globálně. Požadavky provedené na akce, které mají tento filtr použitý, jsou blokované, pokud požadavek neobsahuje platný antiforgery token:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

Atribut ValidateAntiForgeryToken vyžaduje token pro požadavky na metody akce, které označí, včetně požadavků HTTP GET. ValidateAntiForgeryToken Pokud se atribut použije na kontrolery aplikace, můžete ho přepsat pomocí atributuIgnoreAntiforgeryToken.

Automatické ověření tokenů antiforgery pouze pro nebezpečné metody HTTP

Místo široce použitého atributu ValidateAntiForgeryToken a jeho přepsání pomocí IgnoreAntiforgeryToken atributů lze použít atribut AutoValidateAntiforgeryToken . Tento atribut funguje stejně jako ValidateAntiForgeryToken atribut s tím rozdílem, že nevyžaduje tokeny pro požadavky provedené pomocí následujících metod HTTP:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Pro scénáře, které nepoužívají rozhraní API, doporučujeme používat AutoValidateAntiforgeryToken široce. Tento atribut zajišťuje, že akce POST jsou ve výchozím nastavení chráněné. Alternativou je ignorovat antiforgery tokeny ve výchozím nastavení, pokud ValidateAntiForgeryToken není použita u jednotlivých metod akcí. V tomto scénáři je pravděpodobnější, že metoda akce POST zůstane nechráněná omylem, takže aplikace bude zranitelná vůči útokům CSRF. Všechny poST by měly odeslat antiforgery token.

Rozhraní API nemají automatický mechanismus pro odesílání jinécookie části tokenu. Implementace pravděpodobně závisí na implementaci klientského kódu. Tady je několik příkladů:

Příklad na úrovni třídy:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Globální příklad:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Přepsání atributů antiforgery globálního serveru nebo kontroleru

Filtr IgnoreAntiforgeryToken se používá k odstranění potřeby tokenu antiforgery pro danou akci (nebo kontroler). Při použití tento filtr přepíše a AutoValidateAntiforgeryToken filtry ValidateAntiForgeryToken zadané na vyšší úrovni (globálně nebo v kontroleru).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Aktualizace tokenů po ověření

Tokeny by se měly aktualizovat po ověření uživatele přesměrováním uživatele na stránku zobrazení nebo Razor stránky.

JavaScript, AJAX a SPA

V tradičních aplikacích založených na HTML se antiforgery tokeny předávají serveru pomocí skrytých polí formuláře. V moderních aplikacích založených na JavaScriptu a SA se mnoho požadavků provádí programově. Tyto požadavky AJAX můžou k odeslání tokenu použít jiné techniky (například hlavičky požadavků nebo cookies).

Pokud cookiese používají k ukládání ověřovacích tokenů a k ověřování požadavků rozhraní API na serveru, je CSRF potenciálním problémem. Pokud se k uložení tokenu používá místní úložiště, může se zmírnit ohrožení zabezpečení CSRF, protože hodnoty z místního úložiště se na server neodesílají automaticky s každou žádostí. Použití místního úložiště k uložení antiforgery tokenu na klientovi a odeslání tokenu jako hlavičky požadavku je doporučený postup.

JavaScript

Pomocí JavaScriptu se zobrazeními lze token vytvořit pomocí služby v zobrazení. IAntiforgery Vložte službu do zobrazení a zavolejteGetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

Předchozí příklad používá JavaScript ke čtení skryté hodnoty pole hlavičky AJAX POST.

Tento přístup eliminuje potřebu přímo řešit nastavení cookieze serveru nebo je číst z klienta. Pokud však vložení IAntiforgery služby není možné, JavaScript může také přistupovat k tokenům v cookies, získaném z dalšího požadavku na server (obvykle same-origin) a pomocí cookieobsahu tokenu vytvořit hlavičku s hodnotou tokenu.

Za předpokladu, že skript odešle token v hlavičce požadavku s názvem X-XSRF-TOKEN, nakonfigurujte službu antiforgery tak, aby hledala hlavičku X-XSRF-TOKEN :

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

Následující příklad přidá chráněný koncový bod, který zapíše token požadavku do JavaScriptu čitelného cookie:

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

Následující příklad používá JavaScript k vytvoření požadavku AJAX na získání tokenu a provedení dalšího požadavku s příslušnou hlavičkou:

var response = await fetch("/antiforgery/token", {
    method: "GET",
    headers: { "Authorization": authorizationToken }
});

if (response.ok) {
    // https://developer.mozilla.org/docs/web/api/document/cookie
    const xsrfToken = document.cookie
        .split("; ")
        .find(row => row.startsWith("XSRF-TOKEN="))
        .split("=")[1];

    response = await fetch("/JavaScript/FetchEndpoint", {
        method: "POST",
        headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
    });

    if (response.ok) {
        resultElement.innerText = await response.text();
    } else {
        resultElement.innerText = `Request Failed: ${response.status}`
    }
} else {    
    resultElement.innerText = `Request Failed: ${response.status}`
}

Ověřování systému Windows a antiforgery cookies

Při použití ověřování systému Windows musí být koncové body aplikací chráněné proti útokům CSRF stejným způsobem jako u útoků.cookie Prohlížeč implicitně odesílá kontext ověřování na server, takže koncové body musí být chráněné před útoky CSRF.

Rozšířit antiforgery

Tento IAntiforgeryAdditionalDataProvider typ umožňuje vývojářům rozšířit chování systému anti-CSRF tím, že v každém tokenu přetáhne další data. Metoda GetAdditionalData se volá při každém vygenerování tokenu pole a návratová hodnota se vloží do vygenerovaného tokenu. Implementátor by mohl vrátit časové razítko, nece nebo jinou hodnotu a potom volat ValidateAdditionalData ověření těchto dat při ověření tokenu. Uživatelské jméno klienta je již vloženo do vygenerovaných tokenů, takže tyto informace nemusíte obsahovat. Pokud token obsahuje doplňková data, ale není nakonfigurovaná žádná IAntiForgeryAdditionalDataProvider , doplňková data se neověřují.

Další materiály

Padělání požadavků mezi weby (označované také jako XSRF nebo CSRF) je útok na aplikace hostované na webu, kdy škodlivá webová aplikace může ovlivnit interakci mezi klientským prohlížečem a webovou aplikací, která důvěřuje danému prohlížeči. Tyto útoky jsou možné, protože webové prohlížeče automaticky odesílají některé typy ověřovacích tokenů s každou žádostí na web. Tato forma zneužití se také označuje jako útok jedním kliknutím nebo jízda na relaci, protože útok využívá dříve ověřenou relaci uživatele.

Příklad útoku CSRF:

  1. Uživatel se www.good-banking-site.example.com přihlásí pomocí ověřování pomocí formulářů. Server ověřuje uživatele a vydává odpověď, která zahrnuje ověřování cookie. Web je zranitelný vůči útoku, protože důvěřuje všem požadavkem, který obdrží s platným ověřováním cookie.

  2. Uživatel navštíví škodlivý web. www.bad-crook-site.example.com

    Škodlivý web obsahuje www.bad-crook-site.example.comformulář HTML podobný následujícímu příkladu:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Všimněte si, že příspěvky formuláře action na ohrožený web, ne na škodlivý web. Toto je "cross-site" část CSRF.

  3. Uživatel vybere tlačítko Odeslat. Prohlížeč vytvoří požadavek a automaticky zahrne ověřování cookie pro požadovanou doménu. www.good-banking-site.example.com

  4. Požadavek se spustí na www.good-banking-site.example.com serveru s kontextem ověřování uživatele a může provést jakoukoli akci, kterou může ověřený uživatel provést.

Kromě scénáře, ve kterém uživatel vybere tlačítko pro odeslání formuláře, může škodlivý web:

  • Spusťte skript, který automaticky odešle formulář.
  • Odešlete formulář jako požadavek AJAX.
  • Skryjte formulář pomocí šablon stylů CSS.

Tyto alternativní scénáře nevyžadují žádnou akci ani vstup od jiného uživatele, než je počáteční návštěva škodlivého webu.

Použití PROTOKOLU HTTPS nezabrání útoku CSRF. Škodlivý web může požadavek odeslat https://www.good-banking-site.com/ stejně snadno, jako by mohl odeslat nezabezpečený požadavek.

Některé cílové koncové body útoků, které reagují na požadavky GET, v takovém případě je možné k provedení akce použít značku image. Tato forma útoku je běžná na webech fóra, které umožňují obrázky, ale blokují JavaScript. Aplikace, které mění stav požadavků GET, kde se mění proměnné nebo prostředky, jsou zranitelné vůči škodlivým útokům. Požadavky GET, které změní stav, jsou nezabezpečené. Osvědčeným postupem je nikdy změnit stav požadavku GET.

Útoky CSRF jsou možné vůči webovým aplikacím, které používají cookieověřování, protože:

  • cookieÚložiště prohlížečů vydané webovou aplikací
  • Uložené cookierelace cookiezahrnutí pro ověřené uživatele.
  • Prohlížeče odesílají všechny soubory cookiepřidružené k doméně do webové aplikace bez ohledu na to, jak se požadavek na aplikaci vygeneroval v prohlížeči.

Útoky CSRF se ale neomezují pouze na zneužití cookie. Například základní ověřování a ověřování hodnotou hash je také ohroženo. Jakmile se uživatel přihlásí pomocí ověřování Basic nebo Digest, prohlížeč automaticky odešle přihlašovací údaje, dokud relace nedokončí.

V tomto kontextu relace odkazuje na relaci na straně klienta, během které je uživatel ověřen. Nesouvisí s relacemi na straně serveru nebo se ASP.NET Middleware základní relace.

Uživatelé mohou chránit před ohroženími zabezpečení CSRF tím, že podniknou opatření:

  • Po dokončení se odhlaste z webových aplikací.
  • Pravidelně vymažte prohlížeč cookie.

Ohrožení zabezpečení CSRF jsou ale v zásadě problém s webovou aplikací, nikoli koncovým uživatelem.

Základy ověřování

CookieOvěřování na základě je oblíbenou formou ověřování. Systémy ověřování založené na tokenech jsou stále oblíbenější, zejména pro jednostráňové aplikace (SPA).

Když se uživatel ověří pomocí uživatelského jména a hesla, vydá token obsahující ověřovací lístek, který se dá použít k ověřování a autorizaci. Token se uloží jako cookie odesílaný s každým požadavkem, který klient provede. Tento kód generuje Cookie a ověřuje cookie middleware ověřování. Middleware serializuje objekt zabezpečení uživatele do zašifrovaného cookie. V následných požadavcích middleware ověří cookieobjekt zabezpečení , znovu vytvoří objekt zabezpečení a přiřadí objekt zabezpečení k HttpContext.User vlastnosti.

Ověřování na základě tokenů

Když se uživatel ověří, vystavil token (ne antiforgery token). Token obsahuje informace o uživateli ve formě deklarací identity nebo referenčního tokenu, který odkazuje aplikaci na stav uživatele udržovaný v aplikaci. Když se uživatel pokusí získat přístup k prostředku, který vyžaduje ověření, token se odešle do aplikace s extra autorizační hlavičkou ve formě nosného tokenu. Díky tomuto přístupu je aplikace bezstavová. V každém dalším požadavku se token předá v požadavku na ověření na straně serveru. Tento token není šifrovaný, je zakódovaný. Na serveru je token dekódován pro přístup k jeho informacím. Pokud chcete token odeslat při dalších požadavcích, uložte ho do místního úložiště prohlížeče. Nedělejte si starosti s ohrožením zabezpečení CSRF, pokud je token uložený v místním úložišti prohlížeče. CSRF je problém, když je token uložen v .cookie Další informace najdete v ukázce kódu SPA problému GitHubu se dvěma cookiekódy.

Více aplikací hostovaných v jedné doméně

Sdílená hostitelské prostředí jsou zranitelná vůči napadení relace, přihlášení CSRF a dalším útokům.

I když example1.contoso.net a example2.contoso.net jsou různí hostitelé, existuje implicitní vztah důvěryhodnosti mezi hostiteli v rámci *.contoso.net domény. Tento implicitní vztah důvěryhodnosti umožňuje potenciálně nedůvěryhodným hostitelům ovlivnit vzájemné cookievztahy (zásady stejného původu, které řídí požadavky AJAX, nemusí nutně platit pro http cookies).

Útoky, které využívají důvěryhodné cookieservery mezi aplikacemi hostovanými ve stejné doméně, můžou být znemožněné tím, že nesdílí domény. Když je každá aplikace hostovaná ve vlastní doméně, neexistuje žádný implicitní cookie vztah důvěryhodnosti, který by bylo potřeba zneužít.

konfigurace antiforgery ASP.NET Core

Upozorňující

ASP.NET Core implementuje antiforgery pomocí ASP.NET Core Data Protection. Zásobník ochrany dat musí být nakonfigurovaný tak, aby fungoval v serverové farmě. Další informace najdete v tématu Konfigurace ochrany dat.

Do kontejneru injektáže závislostí se přidá middleware antiforgery, když je volána Startup.ConfigureServicesněkterá z následujících rozhraní API:

V ASP.NET Core 2.0 nebo novější vloží FormTagHelper antiforgery tokeny do elementů formuláře HTML. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:

<form method="post">
    ...
</form>

Podobně generuje IHtmlHelper.BeginForm antiforgery tokeny ve výchozím nastavení, pokud metoda formuláře není GET.

Automatické generování tokenů antiforgery pro elementy formuláře HTML nastane, když <form> značka obsahuje method="post" atribut a některé z následujících hodnot jsou pravdivé:

  • Atribut akce je prázdný (action="").
  • Atribut akce není zadán (<form method="post">).

Automatické generování antiforgerických tokenů pro elementy formuláře HTML lze zakázat:

  • Explicitně zakažte antiforgery tokeny s atributem asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • Prvek formuláře je odhlasován od pomocných rutin značek pomocí symbolu odhlásit se:

    <!form method="post">
        ...
    </!form>
    
  • Odeberte zobrazení FormTagHelper . Ze FormTagHelper zobrazení lze odebrat přidáním následující direktivy Razor do zobrazení:

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Poznámka:

Razor Stránky jsou automaticky chráněny před XSRF/CSRF. Další informace najdete v tématu XSRF/CSRF a Razor Pages.

Nejběžnějším přístupem k ochraně před útoky CSRF je použití vzoru tokenů synchronizátoru (STP). STP se používá, když uživatel požádá o stránku s daty formuláře:

  1. Server odešle klientovi token přidružený k identitě aktuálního uživatele.
  2. Klient odešle token zpět na server k ověření.
  3. Pokud server obdrží token, který neodpovídá identitě ověřeného uživatele, žádost se odmítne.

Token je jedinečný a nepředvídatelný. Token lze použít také k zajištění správného sekvencování řady požadavků (například k zajištění pořadí požadavků na stránce 1 > strana 2 > strana 3). Všechny formuláře v šablonách ASP.NET Core MVC a Razor Pages generují antiforgery tokeny. Následující dvojice příkladů zobrazení generuje antiforgery tokeny:

<form asp-controller="Todo" asp-action="Create" method="post">
    ...
</form>

@using (Html.BeginForm("Create", "Todo"))
{
    ...
}

Explicitně přidejte do elementu antiforgery token <form> bez použití pomocných rutin značek s pomocným rutinou @Html.AntiForgeryTokenHTML:

<form action="/" method="post">
    @Html.AntiForgeryToken()
</form>

V každém z předchozích případů ASP.NET Core přidá skryté pole formuláře podobné následujícímu příkladu:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core obsahuje tři filtry pro práci s antiforgery tokeny:

Antiforgery options

Přizpůsobit AntiforgeryOptions v Startup.ConfigureServices:

services.AddAntiforgery(options => 
{
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Nastavte antiforgery Cookie vlastnosti pomocí vlastností CookieBuilder třídy, jak je znázorněno v následující tabulce.

Možnost Popis
Cookie Určuje nastavení použitá k vytvoření antiforgery cookies.
FormFieldName Název skrytého pole formuláře používaného systémem antiforgery k vykreslení tokenů antiforgery v zobrazeních.
HeaderName Název hlavičky používané systémem antiforgery. Pokud nullsystém považuje pouze data formuláře.
SuppressXFrameOptionsHeader Určuje, jestli se má potlačit generování hlavičky X-Frame-Options . Ve výchozím nastavení se hlavička vygeneruje s hodnotou SAMEORIGIN. Výchozí hodnota falseje .

Další informace najdete na webu CookieAuthenticationOptions.

Konfigurace antiforgery funkcí pomocí IAntiforgery

IAntiforgery poskytuje rozhraní API ke konfiguraci antiforgery funkcí. IAntiforgery lze požadovat v Configure metodě Startup třídy.

V následujícím příkladu:

  • Middleware z domovské stránky aplikace se používá k vygenerování antiforgery tokenu a jeho odeslání v odpovědi jako .cookie
  • Token požadavku se odešle jako JavaScript čitelný cookie s výchozí konvencí pojmenování Angular popsanou v části AngularJS .
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

Vyžadovat ověření antiforgery

ValidateAntiForgeryToken je filtr akcí, který lze použít u jednotlivé akce, kontroleru nebo globálně. Požadavky provedené u akcí, které mají tento filtr použitý, jsou blokované, pokud požadavek neobsahuje platný token antiforgery.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
    ManageMessageId? message = ManageMessageId.Error;
    var user = await GetCurrentUserAsync();

    if (user != null)
    {
        var result = 
            await _userManager.RemoveLoginAsync(
                user, account.LoginProvider, account.ProviderKey);

        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            message = ManageMessageId.RemoveLoginSuccess;
        }
    }

    return RedirectToAction(nameof(ManageLogins), new { Message = message });
}

Atribut ValidateAntiForgeryToken vyžaduje token pro požadavky na metody akce, které označí, včetně požadavků HTTP GET. ValidateAntiForgeryToken Pokud se atribut použije na kontrolery aplikace, můžete ho přepsat pomocí atributuIgnoreAntiforgeryToken.

Poznámka:

ASP.NET Core nepodporuje automatické přidávání antiforgery tokenů do požadavků GET.

Automatické ověření tokenů antiforgery pouze pro nebezpečné metody HTTP

ASP.NET aplikace Core negenerují antiforgery tokeny pro bezpečné metody HTTP (GET, HEAD, OPTIONS a TRACE). Místo široce použitého atributu ValidateAntiForgeryToken a jeho přepsání pomocí IgnoreAntiforgeryToken atributů lze použít atribut AutoValidateAntiforgeryToken . Tento atribut funguje stejně jako ValidateAntiForgeryToken atribut s tím rozdílem, že nevyžaduje tokeny pro požadavky provedené pomocí následujících metod HTTP:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Pro scénáře, které nepoužívají rozhraní API, doporučujeme používat AutoValidateAntiforgeryToken široce. Tento atribut zajišťuje, že akce POST jsou ve výchozím nastavení chráněné. Alternativou je ignorovat antiforgery tokeny ve výchozím nastavení, pokud ValidateAntiForgeryToken není použita u jednotlivých metod akcí. V tomto scénáři je pravděpodobnější, že metoda akce POST zůstane nechráněná omylem, takže aplikace bude zranitelná vůči útokům CSRF. Všechny poST by měly odeslat antiforgery token.

Rozhraní API nemají automatický mechanismus pro odesílání jinécookie části tokenu. Implementace pravděpodobně závisí na implementaci klientského kódu. Tady je několik příkladů:

Příklad na úrovni třídy:

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{

Globální příklad:

services.AddControllersWithViews(options =>
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));

Přepsání atributů antiforgery globálního serveru nebo kontroleru

Filtr IgnoreAntiforgeryToken se používá k odstranění potřeby tokenu antiforgery pro danou akci (nebo kontroler). Při použití tento filtr přepíše a AutoValidateAntiforgeryToken filtry ValidateAntiForgeryToken zadané na vyšší úrovni (globálně nebo v kontroleru).

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
    [HttpPost]
    [IgnoreAntiforgeryToken]
    public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
    {
        // no antiforgery token required
    }
}

Aktualizace tokenů po ověření

Tokeny by se měly aktualizovat po ověření uživatele přesměrováním uživatele na stránku zobrazení nebo Razor stránky.

JavaScript, AJAX a SPA

V tradičních aplikacích založených na HTML se antiforgery tokeny předávají serveru pomocí skrytých polí formuláře. V moderních aplikacích založených na JavaScriptu a SA se mnoho požadavků provádí programově. Tyto požadavky AJAX můžou k odeslání tokenu použít jiné techniky (například hlavičky požadavků nebo cookies).

Pokud cookiese používají k ukládání ověřovacích tokenů a k ověřování požadavků rozhraní API na serveru, je CSRF potenciálním problémem. Pokud se k uložení tokenu používá místní úložiště, může se zmírnit ohrožení zabezpečení CSRF, protože hodnoty z místního úložiště se na server neodesílají automaticky s každou žádostí. Použití místního úložiště k uložení antiforgery tokenu na klientovi a odeslání tokenu jako hlavičky požadavku je doporučený postup.

JavaScript

Pomocí JavaScriptu se zobrazeními lze token vytvořit pomocí služby v zobrazení. IAntiforgery Vložte službu do zobrazení a zavolejteGetAndStoreTokens:

@{
    ViewData["Title"] = "AJAX Demo";
}
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

<input type="hidden" id="RequestVerificationToken" 
       name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">

<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<div class="row">
    <p><input type="button" id="antiforgery" value="Antiforgery"></p>
    <script>
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == XMLHttpRequest.DONE) {
                if (xhttp.status == 200) {
                    alert(xhttp.responseText);
                } else {
                    alert('There was an error processing the AJAX request.');
                }
            }
        };

        document.addEventListener('DOMContentLoaded', function() {
            document.getElementById("antiforgery").onclick = function () {
                xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
                xhttp.setRequestHeader("RequestVerificationToken", 
                    document.getElementById('RequestVerificationToken').value);
                xhttp.send();
            }
        });
    </script>
</div>

Tento přístup eliminuje potřebu přímo řešit nastavení cookieze serveru nebo je číst z klienta.

Předchozí příklad používá JavaScript ke čtení skryté hodnoty pole hlavičky AJAX POST.

JavaScript může také přistupovat k tokenům v cookies a pomocí cookieobsahu vytvořit hlavičku s hodnotou tokenu.

context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, 
    new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });

Za předpokladu, že skript požádá o odeslání tokenu v hlavičce s názvem X-CSRF-TOKEN, nakonfigurujte službu antiforgery tak, aby hledala hlavičku X-CSRF-TOKEN :

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");

Následující příklad používá JavaScript k vytvoření požadavku AJAX s příslušnou hlavičkou:

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) === ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) === 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

var csrfToken = getCookie("CSRF-TOKEN");

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
    if (xhttp.readyState === XMLHttpRequest.DONE) {
        if (xhttp.status === 204) {
            alert('Todo item is created successfully.');
        } else {
            alert('There was an error processing the AJAX request.');
        }
    }
};
xhttp.open('POST', '/api/items', true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("X-CSRF-TOKEN", csrfToken);
xhttp.send(JSON.stringify({ "name": "Learn C#" }));

ÚhlovéJS

AngularJS používá konvenci k řešení CSRF. Pokud server odešle cookie s názvem , XSRF-TOKENslužba AngularJS$http přidá cookie hodnotu do hlavičky při odeslání požadavku na server. Jedná se o automatický proces. Klient nemusí explicitně nastavit hlavičku. Název záhlaví je X-XSRF-TOKEN. Server by měl tuto hlavičku rozpoznat a ověřit jeho obsah.

Aby rozhraní API ASP.NET Core fungovalo s touto konvencí při spuštění aplikace:

  • Nakonfigurujte aplikaci tak, aby poskytovala token volaný cookieXSRF-TOKEN.
  • Nakonfigurujte službu antiforgery tak, aby hledala hlavičku s názvem X-XSRF-TOKEN, což je výchozí název hlavičky Angular pro odeslání tokenu XSRF.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (
            string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}

Poznámka:

Pokud je token antiforgery zadaný v hlavičce požadavku i v datové části formuláře, ověří se pouze token v hlavičce.

Ověřování systému Windows a antiforgery cookies

Při použití ověřování systému Windows musí být koncové body aplikací chráněné proti útokům CSRF stejným způsobem jako u útoků.cookie Prohlížeč implicitně odesílá kontext ověřování na server, takže koncové body musí být chráněné před útoky CSRF.

Rozšířit antiforgery

Tento IAntiforgeryAdditionalDataProvider typ umožňuje vývojářům rozšířit chování systému anti-CSRF tím, že v každém tokenu přetáhne další data. Metoda GetAdditionalData se volá při každém vygenerování tokenu pole a návratová hodnota se vloží do vygenerovaného tokenu. Implementátor by mohl vrátit časové razítko, nece nebo jinou hodnotu a potom volat ValidateAdditionalData ověření těchto dat při ověření tokenu. Uživatelské jméno klienta je již vloženo do vygenerovaných tokenů, takže tyto informace nemusíte obsahovat. Pokud token obsahuje doplňková data, ale není nakonfigurovaná žádná IAntiForgeryAdditionalDataProvider , doplňková data se neověřují.

Další materiály