Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Autoři: Fiyaz Hasan a Rick Anderson
Zranitelnost zvaná cross-site request forgery (CSRF) je útok na webové aplikace, kdy škodlivá webová aplikace může ovlivnit interakci mezi klientským prohlížečem a webovou aplikací, která důvěřuje tomuto 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 jednoklikový útok nebo únos relace, 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:
Uživatel se přihlásí k
www.good-banking-site.example.com
pomocí ověření formulářem. 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.Uživatel navštíví škodlivý web.
www.bad-crook-site.example.com
Škodlivý web obsahuje
www.bad-crook-site.example.com
formulář HTML podobný následujícímu příkladu:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.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 to collect your prize!" /> </form>
Všimněte si, že formulář
action
odesílá na ohrožený web, nikoli na škodlivý web. Toto je "cross-site" část CSRF.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
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 odeslat https://www.good-banking-site.example.com/
požadavek stejně snadno, jako by mohl odeslat nezabezpečený požadavek.
Některé útoky cílí na koncové body, které reagují na požadavky GET, v takovém případě lze použít značku image k provedení akce. 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é k ověřování používají soubory cookie, protože:
- Prohlížeče ukládají soubory cookie vydané webovou aplikací.
- Uložené soubory cookie obsahují soubory cookie relace pro ověřené uživatele.
- Prohlížeče odesílají všechny soubory cookie př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 ale nejsou omezené na zneužití souborů cookie. Například základní ověřování a ověřování pomocí digest 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 neskončí.
V tomto kontextu relace odkazuje na relaci na straně klienta, ve které je uživatel ověřen. Nesouvisí s relacemi na straně serveru nebo middlewarem ASP.NET Core Session.
Uživatelé mohou chránit před ohroženími zabezpečení CSRF pomocí bezpečnostních opatření:
- Po dokončení se odhlaste z webových aplikací.
- Pravidelně vymažte soubory cookie prohlížeče.
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í
Cookie-založené ověřování 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).
Cookie-založené ověřování
Když se uživatel přihlásí pomocí uživatelského jména a hesla, je mu vydán token obsahující ověřovací autorizační 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. Generování a ověření tohoto cookie probíhá pomocí autentizačního middlewaru Cookie. Middleware serializuje uživatelský principál do zašifrovaného cookie. V následných požadavcích middleware ověří cookie, znovu vytvoří hlavní objekt a přiřadí tento hlavní objekt k vlastnosti HttpContext.User.
Ověřování na základě tokenů
Když je uživatel ověřen, obdrží token, nikoli 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 další autorizační hlavičkou ve formě tokenu typu Bearer. 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, může kyberattacker načíst libovolnou hodnotu z místního úložiště a odeslat ji sama 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 riziko, když je token uložen v cookie. Další informace najdete v problému GitHubu SPA code sample adds two cookies.
Více aplikací hostovaných v jedné doméně
Sdílené hostitelské prostředí jsou zranitelná vůči únosu relace, CSRF útokům při přihlášení 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 soubory cookie ostatních (zásady stejného původu, které řídí požadavky AJAX, se nemusí nutně vztahovat na soubory cookie HTTP).
Útoky, které zneužívají důvěryhodné soubory cookie mezi aplikacemi hostovanými ve stejné doméně, je možné zabránit 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
Upozornění
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 vkládání závislostí se middleware antiforgery přidá, když je voláno některé z následujících API rozhraní Program.cs
:
Další informace naleznete v části Antiforgery s minimálními API rozhraními.
FormTagHelper vkládá do prvků formulářů HTML tokeny proti padělkům. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:
<form method="post">
<!-- ... -->
</form>
Podobně IHtmlHelper.BeginForm ve výchozím nastavení generuje antiforgery tokeny, 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 vyloučen z pomocníků značek pomocí symbolu ! opt-out symbol:
<!form method="post"> <!-- ... --> </!form>
Odeberte
FormTagHelper
ze zobrazení.FormTagHelper
lze ze zobrazení odebrat přidáním následující direktivy do Razor 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:
- Server odešle klientovi token přidružený k identitě aktuálního uživatele.
- Klient odešle token zpět na server k ověření.
- 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 antiforgery token do prvku <form>
bez použití značkového pomocníka s pomocnou rutinou HTML @Html.AntiForgeryToken
:
<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:
Ochrana proti padělání s AddControllers
Volání AddControllers neaktivuje antiforgery tokeny. AddControllersWithViews musí být volána, aby byla podporována integrovaná antiforgery token.
Více karet prohlížeče a vzor synchronizačního tokenu
Nejsou podporovány více karty přihlášené jako různí uživatelé, nebo přihlášení jako anonymní uživatel.
Nakonfigurujte 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 vlastnosti antiforgery Cookie
pomocí vlastností CookieBuilder třídy, jak je uvedeno v následující tabulce.
Možnost | Popis |
---|---|
Cookie | Určuje nastavení použitá k vytvoření ochranných cookies. |
FormFieldName | Název skrytého pole formuláře používaného systémem antiforgery pro vykreslení tokenů antiforgery v zobrazeních. |
HeaderName | Název hlavičky používané systémem antiforgery. Pokud null , systé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 je false . |
Další informace najdete na webu CookieAuthenticationOptions.
Generování antiforgery tokenů pomocí IAntiforgery
IAntiforgery poskytuje rozhraní API ke konfiguraci funkcí proti padělání.
IAntiforgery
lze požádat v Program.cs
pomocí WebApplication.Services. Následující příklad používá middleware z domovské stránky aplikace k vygenerování antiforgery tokenu 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í cookie s názvem XSRF-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 cookie pojmenovaný XSRF-TOKEN
.
Vyžadovat ověření proti padělání
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. Pokud se atribut ValidateAntiForgeryToken
použije na kontrolery aplikace, můžete ho přepsat pomocí atributu IgnoreAntiforgeryToken
.
Automatické ověření tokenů antiforgery pouze pro nebezpečné metody HTTP
Místo široké aplikace atributu ValidateAntiForgeryToken
a jeho přepsání pomocí atributů IgnoreAntiforgeryToken
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
- Hlavička
- MOŽNOSTI
- 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 POSTy by měly odesílat antiforgery token.
Rozhraní API nemají automatický způsob odeslání části tokenu bez cookie. 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 filtry ValidateAntiForgeryToken
a AutoValidateAntiforgeryToken
zadané na vyšší úrovni (globálně nebo na řadiči).
[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 soubory cookie.
Pokud se soubory cookie 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í anti-forgery tokenu na klientovi a odeslání tokenu hlavičkou požadavku je doporučený postup.
Blazor
Pro více informací si přečtěte ASP.NET Core Blazor autentizaci a autorizaci.
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 nutnost zabývat se přímo nastavením souborů cookie ze serveru nebo jejich čtením z klienta. Pokud však vložení IAntiforgery služby není možné, použijte JavaScript pro přístup k tokenům v souborech cookie:
- Přístupové tokeny v dalším požadavku na server, obvykle
same-origin
. - Použijte obsah cookie k vytvoření hlavičky 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.
Ochrana proti padělání s minimálními rozhraními API
Zavolejte AddAntiforgery a zaregistrujte služby ochrany proti padělání 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:
- Není-li zkráceno provádění zbývající části kanálu požadavku?
- Nastaví IAntiforgeryValidationFeature v HttpContext.Features aktuálního požadavku.
Antiforgery token je ověřen pouze v případě, že:
- Koncový bod obsahuje metadata, která implementují IAntiforgeryMetadata tam, kde
RequiresValidation=true
. - Metoda HTTP přidružená ke koncovému bodu je relevantní metoda HTTP. Všechny relevantní metody jsou metody HTTP s výjimkou TRACE, OPTIONS, HEAD a GET.
- Požadavek je přidružený k platnému koncovému bodu.
Poznámka: Pokud je antiforgery middleware povolen manuálně, musí být spuštěn po autentizačním a autorizačním middlewaru, aby se zabránilo čtení dat formuláře, když uživatel není ověřený.
Ve výchozím nastavení vyžadují minimální rozhraní API, která přijímají data formuláře, ověření tokenu proti padělání.
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 antiforgery 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 se příspěvky odesílají do:
-
/todo
vyžaduje platný token proti padělání. -
/todo2
nevyž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 pro:
-
/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
selže, protože antiforgery není zahrnutý. -
/todo2
z formuláře vytvořeného koncovým bodem/DisableAntiforgery
proběhne úspěšně, protože ochrana proti padělání není vyžadována.
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 zaznamená 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 souborů 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 antifalšování
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, náhodné číslo nebo jinou hodnotu a potom zavolat ValidateAdditionalData k ověření těchto dat, když se token ověřuje. 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é nazývá útokem jedním kliknutím nebo útokem typu session riding, protože útok využívá dříve ověřenou relaci uživatele.
Příklad útoku CSRF:
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.Uživatel navštíví škodlivý web.
www.bad-crook-site.example.com
Škodlivý web obsahuje
www.bad-crook-site.example.com
formulář HTML podobný následujícímu příkladu:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.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 to collect your prize!" /> </form>
Všimněte si, že formulář
action
odesílá na ohrožený web, nikoli na škodlivý web. Toto je "cross-site" část CSRF.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
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 odeslat https://www.good-banking-site.example.com/
požadavek stejně snadno, jako by mohl odeslat nezabezpečený požadavek.
Cílují některé útoky koncové body, které reagují na požadavky GET, v takovém případě lze použít značku obrázku k provedení akce. 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é k ověřování používají soubory cookie, protože:
- Prohlížeče ukládají soubory cookie vydané webovou aplikací.
- Uložené soubory cookie obsahují soubory cookie relace pro ověřené uživatele.
- Prohlížeče odesílají všechny soubory cookie př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 ale nejsou omezené na zneužití souborů cookie. Například základní ověřování a Digest ověřování jsou rovněž ohroženy. 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 neskončí.
V tomto kontextu se relace týká relace na straně klienta, během které je uživatel ověřen. Nesouvisí s relacemi na straně serveru nebo ASP.NET Core Session Middleware.
Uživatelé mohou chránit před ohroženími zabezpečení CSRF pomocí bezpečnostních opatření:
- Po dokončení se odhlaste z webových aplikací.
- Pravidelně vymažte soubory cookie prohlížeče.
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í
Ověřování založené na Cookie je oblíbenou formou autentizace. Systémy ověřování založené na tokenech jsou stále oblíbenější, zejména pro jednostráňové aplikace (SPA).
Cookieověřování na základě
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. Generování a ověřování tohoto cookie je provedeno pomocí autentizačního middleware Cookie. Middleware serializuje uživatelského principála 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ž je uživatel ověřen, je mu vydán token (nikoli 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 dodatečnou autorizační hlavičkou ve formě Bearer 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, může kyberattacker načíst libovolnou hodnotu z místního úložiště a odeslat ji sama 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 problému GitHubu Ukázka kódu SPA přidává dvě soubory cookie.
Více aplikací hostovaných v jedné doméně
Sdílená hostitelská prostředí jsou zranitelná vůči únosu relace, CSRF útokům na přihlašování 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 soubory cookie ostatních (zásady stejného původu, které řídí požadavky AJAX, se nemusí nutně vztahovat na soubory cookie HTTP).
Útoky, které zneužívají důvěryhodné soubory cookie mezi aplikacemi hostovanými ve stejné doméně, je možné zabránit 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
Upozornění
ASP.NET Core implementuje ochranu proti padělání 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 pro injekci závislostí se přidá middleware antiforgery, když je v Program.cs
voláno některé z následujících rozhraní API:
FormTagHelper vkládá do elementů formulářů HTML tokeny proti padělání. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:
<form method="post">
<!-- ... -->
</form>
Podobně generuje IHtmlHelper.BeginForm antiforgery tokeny standardně, 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 vyloučen z Tag Helpers pomocí symbolu pro vyloučení:
<!form method="post"> <!-- ... --> </!form>
Odeberte
FormTagHelper
z pohledu. K odstraněníFormTagHelper
ze zobrazení přidejte do zobrazení Razor následující direktivu:@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:
- Server odešle klientovi token přidružený k identitě aktuálního uživatele.
- Klient odešle token zpět na server k ověření.
- 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 <form>
antiforgery token, aniž byste použili pomocníky značek, s pomocí pomocníka HTML @Html.AntiForgeryToken
.
<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 funkcí AddControllers
Volání AddControllers neaktivuje antiforgery tokeny. AddControllersWithViews musí být zavolána, aby bylo zajištěno integrovaný antifalsifikační token.
Více panelů prohlížeče a synchronizační tokenový model
Pouze naposledy načtená stránka obsahuje platný token proti padělání dle vzoru Synchronizer 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á záložka obsahuje platný token proti padělání.
- Požadavky provedené z dříve načtených záložek 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.
Nakonfigurujte ochranu proti padělání 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 vlastnosti antiforgery Cookie
pomocí vlastností třídy CookieBuilder, jak je znázorněno v následující tabulce.
Možnost | Popis |
---|---|
Cookie | Určuje nastavení použitá k vytvoření ochranných cookies proti falšování. |
FormFieldName | Název skrytého pole formuláře, které systém pro ochranu proti falšování používá k vykreslení ochranných tokenů ve zobrazeních. |
HeaderName | Název hlavičky používané systémem proti padělání. Pokud null , systé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 je false . |
Další informace najdete na webu CookieAuthenticationOptions.
Generování antiforgery tokenů pomocí IAntiforgery
IAntiforgery poskytuje rozhraní API ke konfiguraci funkcí proti padělání.
IAntiforgery
může být žádáno v Program.cs
použitím WebApplication.Services. Následující příklad používá middleware z domovské stránky aplikace k vygenerování antiforgery tokenu 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í cookie pojmenovanou XSRF-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 proti XSRF, která čte cookie pojmenované XSRF-TOKEN
ve výchozím nastavení.
Vyžadovat ověření proti padělání
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. Pokud je atribut ValidateAntiForgeryToken
aplikován na kontrolery aplikace, lze jej přepsat pomocí atributu IgnoreAntiforgeryToken
.
Automaticky validujte tokeny antiforgery pouze pro nebezpečné metody HTTP
Místo širokého použití atributu ValidateAntiForgeryToken
a jeho následného přepisování pomocí atributů IgnoreAntiforgeryToken
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
- HLAVA
- MOŽNOSTI
- 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 token proti padělání.
Rozhraní API nemají automatický mechanismus pro odesílání části tokenu bez cookie. 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). Tento filtr při použití přepíše filtry ValidateAntiForgeryToken
a AutoValidateAntiforgeryToken
zadané na vyšší úrovni (globálně nebo na řadiči).
[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 (například hlavičky požadavku nebo soubory cookie).
Pokud se soubory cookie 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žít místní úložiště k uložení antiforgery tokenu na straně klienta a poslat token jako hlavičku požadavku je doporučený postup.
JavaScript
Pomocí JavaScriptu lze token vytvořit přímo ze zobrazení pomocí služby. 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 nutnost zabývat se přímo nastavením souborů cookie ze serveru nebo jejich čtením z klienta. Pokud však vložení IAntiforgery služby není možné, použijte JavaScript pro přístup k tokenům v souborech cookie:
- Přístupové tokeny v dalším požadavku na server, obvykle
same-origin
. - Použijte obsah cookie k vytvoření hlavičky 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 se token antiforgery zadá jak v hlavičce požadavku, tak v datové části formuláře, ověřuje se pouze token v hlavičce.
Ochrana proti padělání s minimálními rozhraními API
Minimal APIs
nepodporuje použití zahrnutých filtrů (ValidateAntiForgeryToken
AutoValidateAntiforgeryToken
, , 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í 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 souborů 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 protipadělatelský systém
Tento IAntiforgeryAdditionalDataProvider typ umožňuje vývojářům rozšířit chování systému anti-CSRF umožněním uložení a přenosu dalších dat v každém tokenu. 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, nonce nebo jinou hodnotu a potom zavolat ValidateAdditionalData pro 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 typu one-click nebo session riding, protože útok využívá dříve ověřenou relaci uživatele.
Příklad útoku CSRF:
Uživatel se
www.good-banking-site.example.com
přihlásí pomocí formulářového ověřování. 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.Uživatel navštíví škodlivý web.
www.bad-crook-site.example.com
Škodlivý web obsahuje
www.bad-crook-site.example.com
formulář HTML podobný následujícímu příkladu:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.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 to collect your prize!" /> </form>
Všimněte si, že formulář
action
se odesílá na ohrožený web, nikoliv na škodlivý web. Toto je „meziwebová“ část CSRF.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
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 odeslat https://www.good-banking-site.example.com/
požadavek stejně snadno, jako by mohl odeslat nezabezpečený požadavek.
Některé útoky cílí na koncové body, které reagují na požadavky GET; v takovém případě lze k provedení akce použít značku img. 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é k ověřování používají soubory cookie, protože:
- Prohlížeče ukládají soubory cookie vydané webovou aplikací.
- Uložené soubory cookie obsahují soubory cookie relace pro ověřené uživatele.
- Prohlížeče odesílají všechny soubory cookie př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 ale nejsou omezené na zneužití souborů cookie. Například základní ověřování a ověřování typu Digest jsou také zranitelné. 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 neskončí.
V tomto kontextu relace odkazuje na relaci na straně klienta, během které je uživatel ověřen. Nesouvisí s relacemi na straně serveru ani s ASP.NET Core middleware pro relace.
Uživatelé mohou chránit před ohroženími zabezpečení CSRF pomocí bezpečnostních opatření:
- Po dokončení se odhlaste z webových aplikací.
- Pravidelně vymažte soubory cookie prohlížeče.
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).
Cookie-založené ověřování
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 cookie generuje a ověřuje middleware pro ověřování Cookie. Middleware serializuje uživatelský účet do zašifrovaného cookie. V následných požadavcích middleware ověří cookie, znovu vytvoří zástupce a přiřadí ho k vlastnosti HttpContext.User.
Ověřování na základě tokenů
Když je uživatel autentizován, je mu vystaven token (nikoli 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 další autorizační hlavičkou ve formě Bearer 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 githubové diskusi Ukázka kódu SPA přidává dvě cookies.
Více aplikací hostovaných v jedné doméně
Sdílené hostingové prostředí jsou zranitelná vůči únosu relace, CSRF útokům na přihlášení 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 soubory cookie ostatních (zásady stejného původu, které řídí požadavky AJAX, se nemusí nutně vztahovat na soubory cookie HTTP).
Útoky, které zneužívají důvěryhodné soubory cookie mezi aplikacemi hostovanými ve stejné doméně, je možné zabránit 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
Varování
ASP.NET Core implementuje ochranu proti padělání 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.cs
ně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 tokeny pro ochranu před paděláním automaticky, 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 vyřazen z pomocníků značek pomocí symbolu pro vyřazení :
<!form method="post"> <!-- ... --> </!form>
Odstraňte
FormTagHelper
ze zobrazení. OdebráníFormTagHelper
z pohledu lze dosáhnout přidáním následující direktivy do Razor pohledu.@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:
- Server odešle klientovi token přidružený k identitě aktuálního uživatele.
- Klient odešle token zpět na server k ověření.
- 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 antiforgery token do elementu <form>
bez použití pomocníků značek pomocí HTML pomocníka @Html.AntiForgeryToken
.
<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:
- ValidateAntiForgeryToken
- AutoValidateAntiforgeryToken
- IgnoreAntiforgeryToken (Ignorovat token proti padělání)
Antiforgery s funkcí AddControllers
Volání AddControllers nepovoluje antiforgery tokeny. AddControllersWithViews musí být volán, aby byla podporována integrovaná antiforgery tokenu.
Více karet prohlížeče a synchronizační tokenový vzor
Při použití vzoru tokenu synchronizátoru obsahuje pouze naposledy načtená stránka platný token proti padělání. Použití více karet může být problematické. Pokud například uživatel otevře více karet:
- Pouze karta načtená jako poslední obsahuje platný antiforgery token.
- Požadavky provedené z dříve načtených panelů 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.
Konfigurujte antiforgery ochranu 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 vlastnosti antiforgery Cookie
pomocí vlastností třídy CookieBuilder, jak je znázorněno v následující tabulce.
Možnost | Popis |
---|---|
Cookie | Určuje nastavení, která se používají k vytvoření antifalešných cookies. |
FormFieldName | Název skrytého pole formuláře používaného antiforgery systémem k zobrazení antiforgery tokenů ve zobrazeních. |
HeaderName | Název hlavičky používané systémem proti falšování. Pokud null , systém považuje pouze data z 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 je false . |
Další informace najdete na webu CookieAuthenticationOptions.
Generování antiforgery tokenů pomocí IAntiforgery
IAntiforgery poskytuje rozhraní API ke konfiguraci funkcí proti padělání.
IAntiforgery
lze požádat v Program.cs
pomocí WebApplication.Services. Následující příklad používá middleware z domovské stránky aplikace k vygenerování antiforgery tokenu 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í cookie s názvem XSRF-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 proti XSRF, která automaticky čte prvek pojmenovanýcookieXSRF-TOKEN
.
Požadovat ověření proti padělání
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. Pokud je atribut ValidateAntiForgeryToken
aplikován na kontrolery aplikace, lze jej přepsat pomocí atributu IgnoreAntiforgeryToken
.
Automatické ověřování antiforgery tokenů pouze pro nezabezpečené metody HTTP
Místo širšího použití atributu ValidateAntiForgeryToken
a jeho nahrazení IgnoreAntiforgeryToken
atributy 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
- Hlava
- MOŽNOSTI
- 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 tokeny proti padělání 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í ne-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 filtr ValidateAntiForgeryToken
a filtr AutoValidateAntiforgeryToken
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 (například hlavičky požadavku nebo soubory cookie).
Pokud se soubory cookie 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 v rámci zobrazení může být token vytvořen službou přímo v tomto 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 nutnost zabývat se přímo nastavením souborů cookie ze serveru nebo jejich čtením z klienta. Pokud však vložení IAntiforgery služby není možné, JavaScript může také přistupovat k tokenu v souborech cookie, který se získá 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 souborů cookie
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 souborů 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 přenášením dalších dat v každém tokenu. 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, nonce nebo jinou hodnotu a potom volat ValidateAdditionalData k ověření těchto dat, když je token ověřován. 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 pomocí jednoho kliknutí nebo únos relace, protože tento útok využívá dříve ověřenou relaci uživatele.
Příklad útoku CSRF:
Uživatel se přihlásí do
www.good-banking-site.example.com
pomocí ověřování formulářem. 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.Uživatel navštíví škodlivý web.
www.bad-crook-site.example.com
Škodlivý web obsahuje
www.bad-crook-site.example.com
formulář HTML podobný následujícímu příkladu:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.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 to collect your prize!" /> </form>
Všimněte si, že formulář
action
se odesílá na ohrožený web, nikoli na škodlivý web. Toto je "mezi weby" část CSRF.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
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 odeslat https://www.good-banking-site.example.com/
požadavek stejně snadno, jako by mohl odeslat nezabezpečený požadavek.
Některé útoky cílí na koncové body, které reagují na požadavky GET, a v takovém případě lze použít značku obrázku k provedení akce. 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é k ověřování používají soubory cookie, protože:
- Prohlížeče ukládají soubory cookie vydané webovou aplikací.
- Uložené soubory cookie obsahují relační soubory cookie pro ověřené uživatele.
- Prohlížeče odesílají všechny soubory cookie př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 ale nejsou omezené na zneužití souborů cookie. Například ověřování typu Basic a Digest jsou také ohrožena. 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 neskončí.
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 s middleware relací ASP.NET Core.
Uživatelé mohou chránit před ohroženími zabezpečení CSRF pomocí bezpečnostních opatření:
- Po dokončení se odhlaste z webových aplikací.
- Pravidelně vymažte soubory cookie prohlížeče.
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í
Ověřování založené na Cookie 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).
Ověřování na základě Cookie
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. Generování a ověřování tohoto cookie provádí middleware ověřování Cookie. Middleware serializuje uživatelský údaj do zašifrovaného cookie. Při následných požadavcích middleware ověří funkci cookie, znovu vytvoří identitu a přiřadí ji k vlastnosti HttpContext.User.
Ověřování na základě tokenů
Když je uživatel ověřen, je mu vydán token (nejedná se o 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 dodatečnou autorizační hlavičkou ve formě Bearer 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 problému na GitHubu Ukázka kódu SPA přidává dva soubory cookie.
Více aplikací hostovaných v jedné doméně
Sdílená hostingová prostředí jsou zranitelná vůči únosu relace, CSRF při přihlašování 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 soubory cookie ostatních (zásady stejného původu, které řídí požadavky AJAX, se nemusí nutně vztahovat na soubory cookie HTTP).
Útoky, které zneužívají důvěryhodné soubory cookie mezi aplikacemi hostovanými ve stejné doméně, je možné zabránit 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 v ASP.NET Core
Varování
ASP.NET Core implementuje ochranu proti podvržení 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.
Middleware pro ochranu proti padělaní je přidáno do kontejneru pro injektáž závislostí, když je voláno některé z následujících rozhraní API:
V ASP.NET Core 2.0 nebo novější FormTagHelper vloží antiforgery tokeny do HTML formulářových elementů. Následující kód v Razor souboru automaticky generuje antiforgery tokeny:
<form method="post">
...
</form>
Podobně, ve výchozím nastavení generuje IHtmlHelper.BeginForm antiforgery tokeny, 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 vyjmut z pomocníků značek pomocí symbolu odhlášení:
<!form method="post"> ... </!form>
Odstraňte
FormTagHelper
ze zobrazení.FormTagHelper
lze odstranit ze zobrazení přidáním následující direktivy do Razor 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:
- Server odešle klientovi token přidružený k identitě aktuálního uživatele.
- Klient odešle token zpět na server k ověření.
- 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 antiforgery token do elementu <form>
bez použití pomocných rutin značek s HTML pomocnou rutinou @Html.AntiForgeryToken
.
<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:
Možnosti ochrany proti padělání
Přizpůsobit AntiforgeryOptions v Startup.ConfigureServices
:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Nastavte vlastnosti antiforgery Cookie
pomocí vlastností třídy CookieBuilder, 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, které se používá systémem antiforgery ke zobrazení tokenů antiforgery ve vizualizacích. |
HeaderName | Název hlavičky, kterou používá systém antiforgery. Pokud null , systé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 false je . |
Další informace najdete na webu CookieAuthenticationOptions.
Konfigurace funkcí ochrany proti falšování pomocí IAntiforgery
IAntiforgery poskytuje rozhraní API ke konfiguraci funkcí ochrany proti podvržení.
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 tomu, aby vygenerovalo antiforgery token a odeslalo ho v odpovědi jako cookie.
- Token požadavku se odešle jako prvek čitelný v JavaScriptu cookie s výchozí konvencí pojmenování Angular popsannou 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í proti padělání.
ValidateAntiForgeryToken je filtr akcí, který lze použít u jednotlivé akce, kontroleru nebo globálně. Požadavky provedené u akcí, které mají tento filtr aplikovaný, jsou blokovány, pokud požadavek neobsahuje platný antiforgery token.
[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. Pokud se atribt ValidateAntiForgeryToken
použije na kontrolery aplikace, můžete ho přepsat pomocí atributu IgnoreAntiforgeryToken
.
Poznámka:
ASP.NET Core nepodporuje automatické přidávání antiforgery tokenů do požadavků GET.
Automaticky ověřovat tokeny 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 širokého použití atributu ValidateAntiForgeryToken
a následného přepisování atributy IgnoreAntiforgeryToken
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
- MOŽNOSTI
- Trasování
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 token proti padělání.
Rozhraní API nemají automatický mechanismus pro odesílání ne-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 aplikaci tento filtr přepíše filtry ValidateAntiForgeryToken
a AutoValidateAntiforgeryToken
zadané na vyšší úrovni (globálně nebo na řadiči).
[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 mohou k odeslání tokenu použít jiné techniky (například hlavičky požadavku nebo soubory cookie).
Pokud se soubory cookie 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í. Doporučeným postupem je použít místní úložiště pro ukládání antiforgery tokenu na straně klienta a odesílat token jako hlavičku požadavku.
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 nutnost zabývat se přímo nastavením souborů cookie ze serveru nebo jejich čtením 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 souborech cookie 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#" }));
AngularJS
AngularJS používá konvenci k řešení CSRF. Pokud server odešle cookie s názvem XSRF-TOKEN
, servis AngularJS $http
přidá hodnotu cookie 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 nazvaný cookie
XSRF-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ý jak v hlavičce požadavku, tak v datové části formuláře, ověřen je pouze token v hlavičce.
Ověřování systému Windows a soubory cookie pro ochranu proti padělání
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 souborů 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 ochranu proti padělání
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řenese 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, náhodné číslo nebo jinou hodnotu a potom zavolat ValidateAdditionalData pro 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í.