Voorkom Cross-Site Request Forgery (XSRF/CSRF) aanvallen in ASP.NET Core
Door Fiyaz Hasan en Rick Anderson
Aanvraagvervalsing op meerdere sites is een aanval op web-gehoste apps, waarbij een schadelijke web-app invloed kan hebben op de interactie tussen een clientbrowser en een web-app die die browser vertrouwt. Deze aanvallen zijn mogelijk omdat webbrowsers bepaalde typen verificatietokens automatisch verzenden met elke aanvraag naar een website. Deze vorm van misbruik wordt ook wel een aanval met één klik genoemd of sessierijden omdat de aanval gebruikmaakt van de eerder geverifieerde sessie van de gebruiker. Aanvraagvervalsing op meerdere sites wordt ook wel XSRF of CSRF genoemd.
Een voorbeeld van een CSRF-aanval:
Een gebruiker meldt zich aan bij
www.good-banking-site.example.com
met formulierverificatie. De server verifieert de gebruiker en geeft een antwoord met een verificatie cookie. De site is kwetsbaar voor aanvallen omdat deze een aanvraag vertrouwt die wordt ontvangen met een geldige authenticatie cookie.De gebruiker bezoekt een schadelijke site,
www.bad-crook-site.example.com
.De schadelijke site,
www.bad-crook-site.example.com
, bevat een HTML-formulier dat vergelijkbaar is met het volgende voorbeeld:<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>
U ziet dat het formulier met
action
naar de kwetsbare site wordt verzonden, niet naar de schadelijke site. Dit is het 'cross-site'-onderdeel van CSRF.De gebruiker selecteert de knop Verzenden. De browser doet de aanvraag en bevat automatisch de verificatie cookie voor het aangevraagde domein,
www.good-banking-site.example.com
.De aanvraag wordt uitgevoerd op de
www.good-banking-site.example.com
-server met de verificatiecontext van de gebruiker en kan elke actie uitvoeren die een geverifieerde gebruiker mag uitvoeren.
Naast het scenario waarin de gebruiker de knop selecteert om het formulier in te dienen, kan de schadelijke site:
- Voer een script uit waarmee het formulier automatisch wordt verzonden.
- Verzend de inzending van het formulier als een AJAX-aanvraag.
- Verberg het formulier met CSS.
Voor deze alternatieve scenario's is geen actie of invoer van de gebruiker vereist, behalve het aanvankelijk bezoeken van de schadelijke site.
Het gebruik van HTTPS voorkomt geen CSRF-aanval. De schadelijke site kan een https://www.good-banking-site.com/
aanvraag zo eenvoudig verzenden als het een onveilige aanvraag kan verzenden.
Sommige aanvallen richten zich op eindpunten die reageren op GET-aanvragen. In dat geval kan een afbeeldingstag worden gebruikt om de actie uit te voeren. Deze vorm van aanval is gebruikelijk op forumsites die afbeeldingen toestaan, maar JavaScript blokkeren. Apps die de status van GET-aanvragen wijzigen, waarbij variabelen of resources worden gewijzigd, zijn kwetsbaar voor schadelijke aanvallen. GET-aanvragen met een wijzigingsstatus zijn onveilig. Een best practice is om nooit de status van een GET-aanvraag te wijzigen.
CSRF-aanvallen zijn mogelijk tegen web-apps die cookies gebruiken voor verificatie, omdat:
- Browsers slaan cookies op die zijn uitgegeven door een web-app.
- Opgeslagen cookies omvatten sessiecookies voor geverifieerde gebruikers.
- Browsers verzenden alle cookies die zijn gekoppeld aan een domein naar de web-app, ongeacht hoe de aanvraag voor de app in de browser is gegenereerd.
CSRF-aanvallen zijn echter niet beperkt tot het misbruiken van cookies. Basis- en samenvattingsverificatie zijn bijvoorbeeld ook kwetsbaar. Nadat een gebruiker zich heeft aangemeld met Basis- of Digest-authenticatie, worden de referenties automatisch verzonden totdat de sessie eindigt.
In deze context verwijst sessie naar de sessie aan de clientzijde waarin de gebruiker wordt geverifieerd. Het is niet gerelateerd aan sessies aan de serverzijde of ASP.NET Core Session Middleware.
Gebruikers kunnen zich beschermen tegen CSRF-beveiligingsproblemen door voorzorgsmaatregelen te nemen:
- Meld u af bij web-apps wanneer u klaar bent met het gebruik ervan.
- Wis regelmatig browsercookies.
CSRF-beveiligingsproblemen zijn echter fundamenteel een probleem met de web-app, niet de eindgebruiker.
Basisprincipes van verificatie
Cookie-gebaseerde verificatie is een populaire vorm van verificatie. Verificatiesystemen op basis van tokens worden steeds populairder, met name voor SPA's (Single Page Applications).
verificatie op basis van Cookie
Wanneer een gebruiker zich verifieert met behulp van zijn gebruikersnaam en wachtwoord, krijgt deze een token met een verificatieticket. Het token kan worden gebruikt voor verificatie en autorisatie. Het token wordt opgeslagen als een cookie die wordt verzonden bij elke aanvraag die de client doet. Het genereren en valideren van deze cookie wordt uitgevoerd met de Cookie Authentication Middleware. De middleware serialiseert een gebruikersprincipe in een versleutelde cookie. Bij volgende aanvragen valideert de middleware de cookie, creëert de principal opnieuw en wijst de principal toe aan de eigenschap HttpContext.User.
Verificatie op basis van tokens
Wanneer een gebruiker wordt geverifieerd, wordt er een token uitgegeven (geen antiforgery-token). Het token bevat gebruikersgegevens in de vorm van claims of een verwijzingstoken dat de app verwijst naar de gebruikersstatus die in de app wordt onderhouden. Wanneer een gebruiker probeert toegang te krijgen tot een resource waarvoor verificatie is vereist, wordt het token verzonden naar de app met een extra autorisatieheader in de vorm van een Bearer-token. Deze aanpak maakt de app staatloos. In elke volgende aanvraag wordt het token doorgegeven in de aanvraag voor validatie aan de serverzijde. Dit token is niet versleuteld; het is gecodeerd. Op de server wordt het token gedecodeerd om toegang te krijgen tot de gegevens. Als u het token wilt verzenden voor volgende aanvragen, slaat u het token op in de lokale opslag van de browser. Het plaatsen van een token in de lokale opslag van de browser en het ophalen en gebruiken als bearer-token biedt bescherming tegen CSRF-aanvallen. Als de app echter kwetsbaar is voor scriptinjectie via XSS of een gecompromitteerd extern JavaScript-bestand, kan een cyberaanval elke waarde ophalen uit de lokale opslag en deze naar zichzelf verzenden. ASP.NET Core codeert standaard alle uitvoer aan de serverzijde van variabelen, waardoor het risico van XSS wordt verminderd. Als u dit gedrag overschrijft met behulp van Html.Raw- of aangepaste code met niet-vertrouwde invoer, kunt u het risico van XSS verhogen.
Wees niet bezorgd over CSRF-beveiligingsproblemen als het token is opgeslagen in de lokale opslag van de browser. CSRF is een probleem wanneer het token wordt opgeslagen in een cookie. Raadpleeg voor meer informatie het GitHub-issue SPA-codevoorbeeld voegt twee cookies toe.
Meerdere apps die worden gehost in één domein
Gedeelde hostingomgevingen zijn kwetsbaar voor sessiekaping, aanmeld-CSRF en andere aanvallen.
Hoewel example1.contoso.net
en example2.contoso.net
verschillende hosts zijn, is er een impliciete vertrouwensrelatie tussen hosts onder het *.contoso.net
domein. Met deze impliciete vertrouwensrelatie kunnen mogelijk niet-vertrouwde hosts de cookies van elkaar beïnvloeden (hetzelfde origin-beleid dat AJAX-aanvragen regelt, zijn niet noodzakelijkerwijs van toepassing op HTTP-cookies).
Aanvallen die gebruikmaken van vertrouwde cookies tussen apps die in hetzelfde domein worden gehost, kunnen worden voorkomen door geen domeinen te delen. Wanneer elke app wordt gehost in een eigen domein, is er geen impliciete cookie vertrouwensrelatie om misbruik te maken.
Antiforgery in ASP.NET Core
Waarschuwing
ASP.NET Core implementeert antivervalsing met behulp van ASP.NET Core Data Protection-. De gegevensbeveiligingsstack moet zijn geconfigureerd voor gebruik in een serverfarm. Zie Gegevensbeveiliging configurerenvoor meer informatie.
Antiforgery-middleware wordt toegevoegd aan de Dependency Injection container wanneer een van de volgende API's wordt aangeroepen in Program.cs
:
Zie Antiforgery met Minimale API'svoor meer informatie.
De FormTagHelper- voegt antiforgery-tokens toe aan HTML-formulierelementen. Met de volgende markeringen in een Razor-bestand worden automatisch antivervalsingstokens gegenereerd:
<form method="post">
<!-- ... -->
</form>
Op dezelfde manier genereert IHtmlHelper.BeginForm standaard antivervalsingstokens als de methode van het formulier niet GET is.
De automatische generatie van antivervalsingstokens voor HTML-formulierelementen vindt plaats wanneer de tag <form>
het kenmerk method="post"
bevat en een van de volgende waar is:
- Het actiekenmerk is leeg (
action=""
). - Het actiekenmerk wordt niet opgegeven (
<form method="post">
).
Het automatisch genereren van antivervalsingstokens voor HTML-formulierelementen kan worden uitgeschakeld:
Schakel antivervalsingstokens expliciet uit met het kenmerk
asp-antiforgery
:<form method="post" asp-antiforgery="false"> <!-- ... --> </form>
Het formulierelement wordt afgemeld voor Tag Helpers met behulp van de Tag Helper ! opt-out symbool:
<!form method="post"> <!-- ... --> </!form>
Verwijder de
FormTagHelper
uit de weergave. DeFormTagHelper
kan uit een weergave worden verwijderd door de volgende instructie toe te voegen aan de Razor weergave:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Notitie
De Razor pagina's worden automatisch beveiligd tegen XSRF/CSRF. Zie XSRF/CSRF en Razor Pagesvoor meer informatie.
De meest voorkomende benadering voor het beveiligen tegen CSRF-aanvallen is het gebruik van de Synchronisatietokenpatroon (STP). STP wordt gebruikt wanneer de gebruiker een pagina aanvraagt met formuliergegevens:
- De server verzendt een token dat is gekoppeld aan de identity van de huidige gebruiker naar de client.
- De client stuurt het token terug naar de server voor verificatie.
- Als de server een token ontvangt dat niet overeenkomt met de identityvan de geverifieerde gebruiker, wordt de aanvraag geweigerd.
Het token is uniek en onvoorspelbaar. Het token kan ook worden gebruikt om de juiste volgorde van een reeks aanvragen te garanderen (bijvoorbeeld om ervoor te zorgen dat de aanvraagvolgorde van: pagina 1 > pagina 2 > pagina 3). Alle formulieren in ASP.NET Core MVC- en Razor Pages-sjablonen genereren antivervalsingstokens. Met het volgende paar weergavevoorbeelden worden antivervalsingstokens gegenereerd:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Voeg expliciet een antivervalsingstoken toe aan een <form>
-element zonder Tag Helpers te gebruiken met de HTML-helper @Html.AntiForgeryToken
:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
In elk van de voorgaande gevallen voegt ASP.NET Core een verborgen formulierveld toe dat vergelijkbaar is met het volgende voorbeeld:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core bevat drie filters voor het werken met antivervalsingstokens:
Antivervalsing met AddControllers
Het aanroepen van AddControllersschakelt geen antivervalsingstokens in. AddControllersWithViews moet worden aangeroepen om ingebouwde antivervalsingstokenondersteuning aan te bieden.
Meerdere browsertabbladen en het Synchronizertokenpatroon
Meerdere tabbladen die zijn aangemeld als verschillende gebruikers, of één die als anoniem is aangemeld, worden niet ondersteund.
Antiforgery configureren met AntiforgeryOptions
AntiforgeryOptions aanpassen in Program.cs
:
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Stel de antivervalsingseigenschappen Cookie
in met behulp van de eigenschappen van de klasse CookieBuilder, zoals wordt weergegeven in de volgende tabel.
Optie | Beschrijving |
---|---|
Cookie | Bepaalt de instellingen die worden gebruikt om de antivervalsing-cookies te maken. |
FormFieldName | De naam van het verborgen formulierveld dat wordt gebruikt door het antivervalsingssysteem om antiforgerytokens weer te geven in weergaven. |
HeaderName | De naam van de header die wordt gebruikt door het antivervalsingssysteem. Wanneer null het geval is, beschouwt het systeem alleen formuliergegevens. |
SuppressXFrameOptionsHeader | Hiermee geeft u op of het genereren van de X-Frame-Options header moet worden onderdrukt. De header wordt standaard gegenereerd met de waarde SAMEORIGIN. Standaard ingesteld op false . |
Zie CookieAuthenticationOptionsvoor meer informatie.
Antivervalsingstokens genereren met IAntiforgery
IAntiforgery biedt de API voor het configureren van antivervalsingfuncties.
IAntiforgery
kan worden aangevraagd in Program.cs
met behulp van WebApplication.Services. In het volgende voorbeeld wordt middleware van de home-pagina van de app gebruikt om een antiforgery-token te genereren en het als een cookiein het antwoord te verzenden:
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);
});
In het voorgaande voorbeeld wordt een cookie met de naam XSRF-TOKEN
ingesteld. De client kan deze cookie lezen en de waarde ervan opgeven als een header die is gekoppeld aan AJAX-aanvragen. Angular bevat bijvoorbeeld ingebouwde XSRF-beveiliging die standaard een cookie met de naam XSRF-TOKEN
leest.
Antivervalsingsvalidatie vereisen
Het ValidateAntiForgeryToken actiefilter kan worden toegepast op een afzonderlijke actie, een controller of globaal. Aanvragen voor acties waarop dit filter is toegepast, worden geblokkeerd, tenzij de aanvraag een geldig antiforgery-token bevat:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Het kenmerk ValidateAntiForgeryToken
vereist een token voor aanvragen naar de actiemethoden die worden gemarkeerd, inclusief HTTP GET-aanvragen. Als het kenmerk ValidateAntiForgeryToken
wordt toegepast op de controllers van de app, kan dit worden overschreven met het kenmerk IgnoreAntiforgeryToken
.
Antiforgery-tokens alleen automatisch valideren voor onveilige HTTP-methoden
In plaats van het kenmerk ValidateAntiForgeryToken
breed toe te passen en dit vervolgens te overschrijven met IgnoreAntiforgeryToken
kenmerken, kan het kenmerk AutoValidateAntiforgeryToken worden gebruikt. Dit kenmerk werkt identiek aan het kenmerk ValidateAntiForgeryToken
, behalve dat er geen tokens nodig zijn voor aanvragen die zijn gedaan met behulp van de volgende HTTP-methoden:
- TOEVOEGEN
- HOOFD
- OPTIES
- SPOOR
U wordt aangeraden AutoValidateAntiforgeryToken
breed te gebruiken voor niet-API-scenario's. Dit kenmerk zorgt ervoor dat POST-acties standaard worden beveiligd. Het alternatief is om antivervalsingstokens standaard te negeren, tenzij ValidateAntiForgeryToken
wordt toegepast op afzonderlijke actiemethoden. In dit scenario is het waarschijnlijker dat een POST-actiemethode per ongeluk onbeveiligd blijft, waardoor de app kwetsbaar blijft voor CSRF-aanvallen. Alle POST's moeten het antivervalsingstoken verzenden.
API's hebben geen automatisch mechanisme voor het verzenden van het niet-cookie deel van het token. De implementatie is waarschijnlijk afhankelijk van de implementatie van de clientcode. Hieronder ziet u enkele voorbeelden:
Voorbeeld op klasseniveau:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Globaal voorbeeld:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Antiforgery-kenmerken van globale of controller overschrijven
Het IgnoreAntiforgeryToken filter wordt gebruikt om de noodzaak van een antiforgery-token voor een bepaalde actie (of controller) te elimineren. Wanneer dit filter wordt toegepast, overschrijft dit filter ValidateAntiForgeryToken
en AutoValidateAntiforgeryToken
filters die zijn opgegeven op een hoger niveau (globaal of op een controller).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Tokens vernieuwen na verificatie
Tokens moeten worden vernieuwd nadat de gebruiker is geverifieerd door de gebruiker te leiden naar een weergave of Razor pagina.
JavaScript, AJAX en SPAs
In traditionele HTML-apps worden antivervalsingstokens doorgegeven aan de server met behulp van verborgen formuliervelden. In moderne op JavaScript gebaseerde apps en SPA's worden veel aanvragen programmatisch gedaan. Deze AJAX-aanvragen kunnen andere technieken gebruiken, zoals aanvraagheaders of cookies, om het token te verzenden.
Als cookies worden gebruikt om verificatietokens op te slaan en API-aanvragen op de server te verifiëren, is CSRF een potentieel probleem. Als lokale opslag wordt gebruikt om het token op te slaan, kan het csrf-beveiligingsprobleem worden beperkt omdat waarden van lokale opslag niet automatisch met elke aanvraag naar de server worden verzonden. Het gebruik van lokale opslag voor het opslaan van het antiforgery-token op de client en het verzenden van het token als aanvraagheader is een aanbevolen benadering.
Blazor
Zie ASP.NET Core Blazor verificatie- en autorisatie-voor meer informatie.
JavaScript
Met behulp van JavaScript met views kan het token worden gemaakt met behulp van een service vanuit de view. Injecteer de IAntiforgery-service in de weergave en roep GetAndStoreTokensaan:
@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>
}
In het voorgaande voorbeeld wordt JavaScript gebruikt om de verborgen veldwaarde voor de AJAX POST-header te lezen.
Deze aanpak elimineert de noodzaak om rechtstreeks om te gaan met het instellen van cookies van de server of het lezen van deze cookies van de client. Wanneer het injecteren van de IAntiforgery-service echter niet mogelijk is, gebruikt u JavaScript voor toegang tot tokens in cookies:
- Toegangstokens in een extra aanvraag voor de server, meestal
same-origin
. - Gebruik de inhoud van de cookieom een header te maken met de waarde van het token.
Ervan uitgaande dat het script het token verzendt in een aanvraagheader met de naam X-XSRF-TOKEN
, configureert u de antiforgery-service om te zoeken naar de X-XSRF-TOKEN
-header:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
In het volgende voorbeeld wordt een beveiligd eindpunt toegevoegd waarmee het aanvraagtoken naar een javaScript-leesbare cookiewordt geschreven:
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();
In het volgende voorbeeld wordt JavaScript gebruikt om een AJAX-aanvraag te maken om het token te verkrijgen en een andere aanvraag te doen met de juiste header:
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}`
}
Notitie
Wanneer het antivervalsingstoken wordt opgegeven in zowel de verzoekheader als in de inhoud van het formulier, wordt alleen het token in de header gevalideerd.
Antifraudebescherming met minimale API's
Roep AddAntiforgery- en UseAntiforgery(IApplicationBuilder) aan om antivervalsingservices te registreren in DI. Antivervalsingstokens worden gebruikt om aanvallen op aanvraagvervalsing op meerdere siteste beperken.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
app.MapGet("/", () => "Hello World!");
app.Run();
De antiforgery middleware:
- Kortsluit rest?
- Stelt de IAntiforgeryValidationFeature in de HttpContext.Features van het huidige verzoek in.
Het antivervalsingstoken wordt alleen gevalideerd als:
- Het eindpunt bevat metagegevens voor het implementeren van IAntiforgeryMetadata waar
RequiresValidation=true
. - De HTTP-methode die aan het eindpunt is gekoppeld, is een relevante HTTP-methode. De relevante methoden zijn allemaal HTTP-methoden, met uitzondering van TRACE, OPTIONS, HEAD en GET.
- De aanvraag is gekoppeld aan een geldig eindpunt.
Opmerking: wanneer deze handmatig is ingeschakeld, moet de antiforgery-middleware worden uitgevoerd na de verificatie- en autorisatie-middleware om te voorkomen dat formuliergegevens worden gelezen wanneer de gebruiker niet is geverifieerd.
Standaard vereisen minimale API's die formuliergegevens accepteren de validatie van antiforgerytokens.
Houd rekening met de volgende GenerateForm
methode:
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>
";
}
De voorgaande code heeft drie argumenten, de actie, het antivervalsingstoken en een bool
die aangeeft of het token moet worden gebruikt.
Bekijk het volgende voorbeeld:
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>
";
}
}
In de voorgaande code plaatst u het volgende in:
- Voor
/todo
is een geldig anti-vervalsings token vereist. -
/todo2
geen een geldig antiforgery-token vereisen omdatDisableAntiforgery
wordt aangeroepen.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Een POST naar:
-
/todo
van het formulier dat door het/
-eindpunt is gegenereerd, is succesvol omdat het anti-vervalsingstoken geldig is. -
/todo
van het formulier dat door de/SkipToken
is gegenereerd, mislukt omdat de antivervalsing niet is opgenomen. -
/todo2
van het door het/DisableAntiforgery
-eindpunt gegenereerde formulier slaagt omdat het antiforgeermechanisme niet vereist is.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Wanneer een formulier wordt verzonden zonder een geldig antiforgery-token:
- In de ontwikkelomgeving wordt een uitzondering opgeworpen.
- In de productieomgeving wordt een bericht vastgelegd.
Windows-verificatie en antivervalsingscookies
Wanneer u Windows-verificatie gebruikt, moeten toepassingseindpunten worden beveiligd tegen CSRF-aanvallen op dezelfde manier als voor cookies. De browser verzendt impliciet de verificatiecontext naar de server en eindpunten moeten worden beveiligd tegen CSRF-aanvallen.
Antiforgery uitbreiden
Met het type IAntiforgeryAdditionalDataProvider kunnen ontwikkelaars het gedrag van het anti-CSRF-systeem uitbreiden door extra gegevens in elk token uit te wisselen. De methode GetAdditionalData wordt aangeroepen telkens wanneer een veldtoken wordt gegenereerd en de retourwaarde wordt ingesloten in het gegenereerde token. Een implementeerfunctie kan een tijdstempel, een nonce of een andere waarde retourneren en vervolgens ValidateAdditionalData aanroepen om deze gegevens te valideren wanneer het token wordt gevalideerd. De gebruikersnaam van de client is al ingesloten in de gegenereerde tokens, dus u hoeft deze informatie niet op te nemen. Als een token aanvullende gegevens bevat, maar geen IAntiForgeryAdditionalDataProvider
is geconfigureerd, worden de aanvullende gegevens niet gevalideerd.
Aanvullende informatiebronnen
Cross-site request forgery (ook wel bekend als XSRF of CSRF) is een aanval op web-gehoste apps waarbij een schadelijke web-app invloed kan hebben op de interactie tussen een clientbrowser en een web-app die die browser vertrouwt. Deze aanvallen zijn mogelijk omdat webbrowsers bepaalde typen verificatietokens automatisch verzenden met elke aanvraag naar een website. Deze vorm van misbruik wordt ook wel een aanval met één klik genoemd of sessierijden omdat de aanval gebruikmaakt van de eerder geverifieerde sessie van de gebruiker.
Een voorbeeld van een CSRF-aanval:
Een gebruiker meldt zich aan bij
www.good-banking-site.example.com
met formulierverificatie. De server verifieert de gebruiker en geeft een antwoord met een verificatie cookie. De site is kwetsbaar voor aanvallen omdat deze een aanvraag vertrouwt die wordt ontvangen met een geldige authenticatie cookie.De gebruiker bezoekt een schadelijke site,
www.bad-crook-site.example.com
.De schadelijke site,
www.bad-crook-site.example.com
, bevat een HTML-formulier dat vergelijkbaar is met het volgende voorbeeld:<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>
U ziet dat het formulier met
action
naar de kwetsbare site wordt verzonden, niet naar de schadelijke site. Dit is het 'cross-site'-onderdeel van CSRF.De gebruiker selecteert de knop Verzenden. De browser doet de aanvraag en bevat automatisch de verificatie cookie voor het aangevraagde domein,
www.good-banking-site.example.com
.De aanvraag wordt uitgevoerd op de
www.good-banking-site.example.com
-server met de verificatiecontext van de gebruiker en kan elke actie uitvoeren die een geverifieerde gebruiker mag uitvoeren.
Naast het scenario waarin de gebruiker de knop selecteert om het formulier in te dienen, kan de schadelijke site:
- Voer een script uit waarmee het formulier automatisch wordt verzonden.
- Verzend de inzending van het formulier als een AJAX-aanvraag.
- Verberg het formulier met CSS.
Voor deze alternatieve scenario's is geen actie of invoer van de gebruiker vereist, behalve het aanvankelijk bezoeken van de schadelijke site.
Het gebruik van HTTPS voorkomt geen CSRF-aanval. De schadelijke site kan een https://www.good-banking-site.com/
aanvraag net zo eenvoudig verzenden als een onveilige aanvraag kan verzenden.
Sommige aanvallen richten zich op eindpunten die reageren op GET-aanvragen. In dat geval kan een afbeeldingstag worden gebruikt om de actie uit te voeren. Deze vorm van aanval is gebruikelijk op forumsites die afbeeldingen toestaan, maar JavaScript blokkeren. Apps die de status van GET-aanvragen wijzigen, waarbij variabelen of resources worden gewijzigd, zijn kwetsbaar voor schadelijke aanvallen. GET-aanvragen met een wijzigingsstatus zijn onveilig. Een best practice is om nooit de status van een GET-aanvraag te wijzigen.
CSRF-aanvallen zijn mogelijk tegen web-apps die cookies gebruiken voor verificatie, omdat:
- Browsers slaan cookies op die zijn uitgegeven door een web-app.
- Opgeslagen cookies omvatten sessiecookies voor geverifieerde gebruikers.
- Browsers verzenden alle cookies die zijn gekoppeld aan een domein naar de web-app, ongeacht hoe de aanvraag voor de app in de browser is gegenereerd.
CSRF-aanvallen zijn echter niet beperkt tot het misbruiken van cookies. Basis- en samenvattingsverificatie zijn bijvoorbeeld ook kwetsbaar. Nadat een gebruiker zich heeft aangemeld met Basis- of Digest-authenticatie, worden de referenties automatisch verzonden totdat de sessie eindigt.
In deze context verwijst sessie naar de sessie aan de clientzijde waarin de gebruiker wordt geverifieerd. Het is niet gerelateerd aan sessies aan de serverzijde of ASP.NET Core Session Middleware.
Gebruikers kunnen zich beschermen tegen CSRF-beveiligingsproblemen door voorzorgsmaatregelen te nemen:
- Meld u af bij web-apps wanneer u klaar bent met het gebruik ervan.
- Wis regelmatig browsercookies.
CSRF-beveiligingsproblemen zijn echter fundamenteel een probleem met de web-app, niet de eindgebruiker.
Basisprincipes van verificatie
Cookie-gebaseerde verificatie is een populaire vorm van verificatie. Verificatiesystemen op basis van tokens worden steeds populairder, met name voor SPA's (Single Page Applications).
verificatie op basis van Cookie
Wanneer een gebruiker zich verifieert met behulp van zijn gebruikersnaam en wachtwoord, wordt er een token uitgegeven met een verificatieticket dat kan worden gebruikt voor verificatie en autorisatie. Het token wordt opgeslagen als een cookie die wordt verzonden bij elke aanvraag die de client doet. Het genereren en valideren van deze cookie wordt uitgevoerd door de Cookie Authentication Middleware. De middleware serialiseert een gebruikersprincipe in een versleutelde cookie. Bij volgende aanvragen valideert de middleware de cookie, creëert de principal opnieuw en wijst de principal toe aan de eigenschap HttpContext.User.
Verificatie op basis van tokens
Wanneer een gebruiker wordt geverifieerd, wordt er een token uitgegeven (geen antiforgery-token). Het token bevat gebruikersgegevens in de vorm van claims of een verwijzingstoken dat de app verwijst naar de gebruikersstatus die in de app wordt onderhouden. Wanneer een gebruiker probeert toegang te krijgen tot een resource waarvoor verificatie is vereist, wordt het token verzonden naar de app met een extra autorisatieheader in de vorm van een Bearer-token. Deze aanpak maakt de app staatloos. In elke volgende aanvraag wordt het token doorgegeven in de aanvraag voor validatie aan de serverzijde. Dit token is niet versleuteld; het is gecodeerd. Op de server wordt het token gedecodeerd om toegang te krijgen tot de gegevens. Als u het token wilt verzenden voor volgende aanvragen, slaat u het token op in de lokale opslag van de browser. Het plaatsen van een token in de lokale opslag van de browser en het ophalen en gebruiken als bearer-token biedt bescherming tegen CSRF-aanvallen. Als de app echter kwetsbaar is voor scriptinjectie via XSS of een gecompromitteerd extern Javascript-bestand, kan een cyberattacker elke waarde ophalen uit de lokale opslag en deze naar zichzelf verzenden. ASP.NET Core codeert standaard alle uitvoer aan de serverzijde van variabelen, waardoor het risico van XSS wordt verminderd. Als u dit gedrag overschrijft met behulp van Html.Raw- of aangepaste code met niet-vertrouwde invoer, kunt u het risico van XSS verhogen.
Wees niet bezorgd over CSRF-beveiligingsproblemen als het token is opgeslagen in de lokale opslag van de browser. CSRF is een probleem wanneer het token wordt opgeslagen in een cookie. Raadpleeg voor meer informatie het GitHub-issue SPA-codevoorbeeld voegt twee cookies toe.
Meerdere apps die worden gehost in één domein
Gedeelde hostingomgevingen zijn kwetsbaar voor sessiekaaking, aanmeldings-CSRF en andere aanvallen.
Hoewel example1.contoso.net
en example2.contoso.net
verschillende hosts zijn, is er een impliciete vertrouwensrelatie tussen hosts onder het *.contoso.net
domein. Met deze impliciete vertrouwensrelatie kunnen mogelijk niet-vertrouwde hosts de cookies van elkaar beïnvloeden (hetzelfde origin-beleid dat AJAX-aanvragen regelt, zijn niet noodzakelijkerwijs van toepassing op HTTP-cookies).
Aanvallen die gebruikmaken van vertrouwde cookies tussen apps die in hetzelfde domein worden gehost, kunnen worden voorkomen door geen domeinen te delen. Wanneer elke app wordt gehost in een eigen domein, is er geen impliciete cookie vertrouwensrelatie om misbruik te maken.
Antiforgery in ASP.NET Core
Waarschuwing
ASP.NET Core implementeert antivervalsing met behulp van ASP.NET Core Data Protection-. De gegevensbeveiligingsstack moet zijn geconfigureerd voor gebruik in een serverfarm. Zie Gegevensbeveiliging configurerenvoor meer informatie.
Antiforgery-middleware wordt toegevoegd aan de Dependency Injection container wanneer een van de volgende API's wordt aangeroepen in Program.cs
:
De FormTagHelper- voegt antiforgery-tokens toe aan HTML-formulierelementen. Met de volgende markeringen in een Razor-bestand worden automatisch antivervalsingstokens gegenereerd:
<form method="post">
<!-- ... -->
</form>
Op dezelfde manier genereert IHtmlHelper.BeginForm standaard antivervalsingstokens als de methode van het formulier niet GET is.
De automatische generatie van antivervalsingstokens voor HTML-formulierelementen vindt plaats wanneer de tag <form>
het kenmerk method="post"
bevat en een van de volgende waar is:
- Het actiekenmerk is leeg (
action=""
). - Het actiekenmerk wordt niet opgegeven (
<form method="post">
).
Het automatisch genereren van antivervalsingstokens voor HTML-formulierelementen kan worden uitgeschakeld:
Schakel antivervalsingstokens expliciet uit met het kenmerk
asp-antiforgery
:<form method="post" asp-antiforgery="false"> <!-- ... --> </form>
Het formulierelement wordt afgemeld voor Tag Helpers met behulp van de Tag Helper ! opt-out symbool:
<!form method="post"> <!-- ... --> </!form>
Verwijder de
FormTagHelper
uit de weergave. DeFormTagHelper
kan uit een weergave worden verwijderd door de volgende instructie toe te voegen aan de Razor weergave:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Notitie
De Razor pagina's worden automatisch beveiligd tegen XSRF/CSRF. Zie XSRF/CSRF en Razor Pagesvoor meer informatie.
De meest voorkomende benadering voor het verdedigen van CSRF-aanvallen is het gebruik van de Synchroontokenpatroon (STP). STP wordt gebruikt wanneer de gebruiker een pagina aanvraagt met formuliergegevens:
- De server verzendt een token dat is gekoppeld aan de identity van de huidige gebruiker naar de client.
- De client stuurt het token terug naar de server voor verificatie.
- Als de server een token ontvangt dat niet overeenkomt met de identityvan de geverifieerde gebruiker, wordt de aanvraag geweigerd.
Het token is uniek en onvoorspelbaar. Het token kan ook worden gebruikt om de juiste volgorde van een reeks aanvragen te garanderen (bijvoorbeeld om ervoor te zorgen dat de aanvraagvolgorde van: pagina 1 > pagina 2 > pagina 3). Alle formulieren in ASP.NET Core MVC- en Razor Pages-sjablonen genereren antivervalsingstokens. Met het volgende paar weergavevoorbeelden worden antivervalsingstokens gegenereerd:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Voeg expliciet een antivervalsingstoken toe aan een <form>
-element zonder Tag Helpers te gebruiken met de HTML-helper @Html.AntiForgeryToken
:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
In elk van de voorgaande gevallen voegt ASP.NET Core een verborgen formulierveld toe dat vergelijkbaar is met het volgende voorbeeld:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core bevat drie filters voor het werken met antivervalsingstokens:
Antivervalsing met AddControllers
Het aanroepen van AddControllersschakelt geen antivervalsingstokens in. AddControllersWithViews moet worden aangeroepen om ingebouwde antivervalsingstokenondersteuning aan te bieden.
Meerdere browsertabbladen en het Synchronizertokenpatroon
Met het synchronisatiepatroon bevat alleen de laatst geladen pagina een geldig antiforgery-token. Het gebruik van meerdere tabbladen kan problematisch zijn. Als een gebruiker bijvoorbeeld meerdere tabbladen opent:
- Alleen het laatst geladen tabblad bevat een geldig antiforgery-token.
- Aanvragen van eerder geladen tabbladen mislukken met een fout:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Overweeg alternatieve CSRF-beveiligingspatronen als dit een probleem vormt.
Antiforgery configureren met AntiforgeryOptions
AntiforgeryOptions aanpassen in Program.cs
:
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Stel de antivervalsingseigenschappen Cookie
in met behulp van de eigenschappen van de klasse CookieBuilder, zoals wordt weergegeven in de volgende tabel.
Optie | Beschrijving |
---|---|
Cookie | Bepaalt de instellingen die worden gebruikt om de antivervalsing-cookies te maken. |
FormFieldName | De naam van het verborgen formulierveld dat wordt gebruikt door het antivervalsingssysteem om antiforgerytokens weer te geven in weergaven. |
HeaderName | De naam van de header die wordt gebruikt door het antivervalsingssysteem. Wanneer null het geval is, beschouwt het systeem alleen formuliergegevens. |
SuppressXFrameOptionsHeader | Hiermee geeft u op of het genereren van de X-Frame-Options header moet worden onderdrukt. De header wordt standaard gegenereerd met de waarde SAMEORIGIN. Standaard ingesteld op false . |
Zie CookieAuthenticationOptionsvoor meer informatie.
Antivervalsingstokens genereren met IAntiforgery
IAntiforgery biedt de API voor het configureren van antivervalsingfuncties.
IAntiforgery
kan worden aangevraagd in Program.cs
met behulp van WebApplication.Services. In het volgende voorbeeld wordt middleware van de home-pagina van de app gebruikt om een antiforgery-token te genereren en het als een cookiein het antwoord te verzenden:
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);
});
In het voorgaande voorbeeld wordt een cookie met de naam XSRF-TOKEN
ingesteld. De client kan deze cookie lezen en de waarde ervan opgeven als een header die is gekoppeld aan AJAX-aanvragen. Angular bevat bijvoorbeeld ingebouwde XSRF-beveiliging die standaard een cookie met de naam XSRF-TOKEN
leest.
Antivervalsingsvalidatie vereisen
Het ValidateAntiForgeryToken actiefilter kan worden toegepast op een afzonderlijke actie, een controller of globaal. Aanvragen voor acties waarop dit filter is toegepast, worden geblokkeerd, tenzij de aanvraag een geldig antiforgery-token bevat:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Het kenmerk ValidateAntiForgeryToken
vereist een token voor aanvragen naar de actiemethoden die worden gemarkeerd, inclusief HTTP GET-aanvragen. Als het kenmerk ValidateAntiForgeryToken
wordt toegepast op de controllers van de app, kan dit worden overschreven met het kenmerk IgnoreAntiforgeryToken
.
Antiforgery-tokens alleen automatisch valideren voor onveilige HTTP-methoden
In plaats van het kenmerk ValidateAntiForgeryToken
breed toe te passen en dit vervolgens te overschrijven met IgnoreAntiforgeryToken
kenmerken, kan het kenmerk AutoValidateAntiforgeryToken worden gebruikt. Dit kenmerk werkt identiek aan het kenmerk ValidateAntiForgeryToken
, behalve dat er geen tokens nodig zijn voor aanvragen die zijn gedaan met behulp van de volgende HTTP-methoden:
- TOEVOEGEN
- HOOFD
- OPTIES
- SPOOR
U wordt aangeraden AutoValidateAntiforgeryToken
breed te gebruiken voor niet-API-scenario's. Dit kenmerk zorgt ervoor dat POST-acties standaard worden beveiligd. Het alternatief is om antivervalsingstokens standaard te negeren, tenzij ValidateAntiForgeryToken
wordt toegepast op afzonderlijke actiemethoden. In dit scenario is het waarschijnlijker dat een POST-actiemethode per ongeluk onbeveiligd blijft, waardoor de app kwetsbaar blijft voor CSRF-aanvallen. Alle POST's moeten het antivervalsingstoken verzenden.
API's hebben geen automatisch mechanisme voor het verzenden van het niet-cookie deel van het token. De implementatie is waarschijnlijk afhankelijk van de implementatie van de clientcode. Hieronder ziet u enkele voorbeelden:
Voorbeeld op klasseniveau:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Globaal voorbeeld:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Antiforgery-kenmerken van globale of controller overschrijven
Het IgnoreAntiforgeryToken filter wordt gebruikt om de noodzaak van een antiforgery-token voor een bepaalde actie (of controller) te elimineren. Wanneer dit filter wordt toegepast, overschrijft dit filter ValidateAntiForgeryToken
en AutoValidateAntiforgeryToken
filters die zijn opgegeven op een hoger niveau (globaal of op een controller).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Tokens vernieuwen na verificatie
Tokens moeten worden vernieuwd nadat de gebruiker is geverifieerd door de gebruiker te leiden naar een weergave of Razor pagina.
JavaScript, AJAX en SPAs
In traditionele HTML-apps worden antivervalsingstokens doorgegeven aan de server met behulp van verborgen formuliervelden. In moderne op JavaScript gebaseerde apps en SPA's worden veel aanvragen programmatisch gedaan. Deze AJAX-aanvragen kunnen andere technieken (zoals aanvraagheaders of cookies) gebruiken om het token te verzenden.
Als cookies worden gebruikt om verificatietokens op te slaan en API-aanvragen op de server te verifiëren, is CSRF een potentieel probleem. Als lokale opslag wordt gebruikt om het token op te slaan, kan het csrf-beveiligingsprobleem worden beperkt omdat waarden van lokale opslag niet automatisch met elke aanvraag naar de server worden verzonden. Het gebruik van lokale opslag voor het opslaan van het antiforgery-token op de client en het verzenden van het token als aanvraagheader is een aanbevolen benadering.
JavaScript
Met behulp van JavaScript met views kan het token worden gemaakt met behulp van een service vanuit de view. Injecteer de IAntiforgery-service in de weergave en roep GetAndStoreTokensaan:
@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>
}
In het voorgaande voorbeeld wordt JavaScript gebruikt om de verborgen veldwaarde voor de AJAX POST-header te lezen.
Deze aanpak elimineert de noodzaak om rechtstreeks om te gaan met het instellen van cookies van de server of het lezen van deze cookies van de client. Wanneer het injecteren van de IAntiforgery-service echter niet mogelijk is, gebruikt u JavaScript voor toegang tot tokens in cookies:
- Toegangstokens in een extra aanvraag voor de server, meestal
same-origin
. - Gebruik de inhoud van de cookieom een header te maken met de waarde van het token.
Ervan uitgaande dat het script het token verzendt in een aanvraagheader met de naam X-XSRF-TOKEN
, configureert u de antiforgery-service om te zoeken naar de X-XSRF-TOKEN
-header:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
In het volgende voorbeeld wordt een beveiligd eindpunt toegevoegd waarmee het aanvraagtoken naar een javaScript-leesbare cookiewordt geschreven:
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();
In het volgende voorbeeld wordt JavaScript gebruikt om een AJAX-aanvraag te maken om het token te verkrijgen en een andere aanvraag te doen met de juiste header:
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}`
}
Notitie
Wanneer het antivervalsingstoken wordt opgegeven in zowel de verzoekheader als in de inhoud van het formulier, wordt alleen het token in de header gevalideerd.
Antifraudebescherming met minimale API's
Minimal APIs
bieden echter geen ondersteuning voor het gebruik van de opgenomen filters (ValidateAntiForgeryToken
, AutoValidateAntiforgeryToken
, IgnoreAntiforgeryToken
), maar IAntiforgery de vereiste API's biedt om een aanvraag te valideren.
In het volgende voorbeeld wordt een filter gemaakt waarmee het antivervalsingstoken wordt gevalideerd:
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);
});
}
}
Het filter kan vervolgens worden toegepast op een eindpunt:
app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
.RequireAuthorization()
.ValidateAntiforgery();
Windows-verificatie en antivervalsingscookies
Wanneer u Windows-verificatie gebruikt, moeten toepassingseindpunten worden beveiligd tegen CSRF-aanvallen op dezelfde manier als voor cookies. De browser verzendt impliciet de verificatiecontext naar de server en eindpunten moeten worden beveiligd tegen CSRF-aanvallen.
Antiforgery uitbreiden
Met het type IAntiforgeryAdditionalDataProvider kunnen ontwikkelaars het gedrag van het anti-CSRF-systeem uitbreiden door extra gegevens in elk token uit te wisselen. De methode GetAdditionalData wordt aangeroepen telkens wanneer een veldtoken wordt gegenereerd en de retourwaarde wordt ingesloten in het gegenereerde token. Een implementeerfunctie kan een tijdstempel, een nonce of een andere waarde retourneren en vervolgens ValidateAdditionalData aanroepen om deze gegevens te valideren wanneer het token wordt gevalideerd. De gebruikersnaam van de client is al ingesloten in de gegenereerde tokens, dus u hoeft deze informatie niet op te nemen. Als een token aanvullende gegevens bevat, maar geen IAntiForgeryAdditionalDataProvider
is geconfigureerd, worden de aanvullende gegevens niet gevalideerd.
Aanvullende informatiebronnen
Cross-site request forgery (ook wel bekend als XSRF of CSRF) is een aanval op web-gehoste apps waarbij een schadelijke web-app invloed kan hebben op de interactie tussen een clientbrowser en een web-app die die browser vertrouwt. Deze aanvallen zijn mogelijk omdat webbrowsers bepaalde typen verificatietokens automatisch verzenden met elke aanvraag naar een website. Deze vorm van misbruik wordt ook wel een aanval met één klik genoemd of sessierijden omdat de aanval gebruikmaakt van de eerder geverifieerde sessie van de gebruiker.
Een voorbeeld van een CSRF-aanval:
Een gebruiker meldt zich aan bij
www.good-banking-site.example.com
met formulierverificatie. De server verifieert de gebruiker en geeft een antwoord met een verificatie cookie. De site is kwetsbaar voor aanvallen omdat deze een aanvraag vertrouwt die wordt ontvangen met een geldige authenticatie cookie.De gebruiker bezoekt een schadelijke site,
www.bad-crook-site.example.com
.De schadelijke site,
www.bad-crook-site.example.com
, bevat een HTML-formulier dat vergelijkbaar is met het volgende voorbeeld:<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>
U ziet dat het formulier met
action
naar de kwetsbare site wordt verzonden, niet naar de schadelijke site. Dit is het 'cross-site'-onderdeel van CSRF.De gebruiker selecteert de knop Verzenden. De browser doet de aanvraag en bevat automatisch de verificatie cookie voor het aangevraagde domein,
www.good-banking-site.example.com
.De aanvraag wordt uitgevoerd op de
www.good-banking-site.example.com
-server met de verificatiecontext van de gebruiker en kan elke actie uitvoeren die een geverifieerde gebruiker mag uitvoeren.
Naast het scenario waarin de gebruiker de knop selecteert om het formulier in te dienen, kan de schadelijke site:
- Voer een script uit waarmee het formulier automatisch wordt verzonden.
- Verzend de inzending van het formulier als een AJAX-aanvraag.
- Verberg het formulier met CSS.
Voor deze alternatieve scenario's is geen actie of invoer van de gebruiker vereist, behalve het aanvankelijk bezoeken van de schadelijke site.
Het gebruik van HTTPS voorkomt geen CSRF-aanval. De schadelijke site kan een https://www.good-banking-site.com/
aanvraag net zo eenvoudig verzenden als een onveilige aanvraag kan verzenden.
Sommige aanvallen richten zich op eindpunten die reageren op GET-aanvragen. In dat geval kan een afbeeldingstag worden gebruikt om de actie uit te voeren. Deze vorm van aanval is gebruikelijk op forumsites die afbeeldingen toestaan, maar JavaScript blokkeren. Apps die de status van GET-aanvragen wijzigen, waarbij variabelen of resources worden gewijzigd, zijn kwetsbaar voor schadelijke aanvallen. GET-aanvragen met een wijzigingsstatus zijn onveilig. Een best practice is om nooit de status van een GET-aanvraag te wijzigen.
CSRF-aanvallen zijn mogelijk tegen web-apps die cookies gebruiken voor verificatie, omdat:
- Browsers slaan cookies op die zijn uitgegeven door een web-app.
- Opgeslagen cookies omvatten sessiecookies voor geverifieerde gebruikers.
- Browsers verzenden alle cookies die zijn gekoppeld aan een domein naar de web-app, ongeacht hoe de aanvraag voor de app in de browser is gegenereerd.
CSRF-aanvallen zijn echter niet beperkt tot het misbruiken van cookies. Basis- en samenvattingsverificatie zijn bijvoorbeeld ook kwetsbaar. Nadat een gebruiker zich heeft aangemeld met Basis- of Digest-authenticatie, worden de referenties automatisch verzonden totdat de sessie eindigt.
In deze context verwijst sessie naar de sessie aan de clientzijde waarin de gebruiker wordt geverifieerd. Het is niet gerelateerd aan sessies aan de serverzijde of ASP.NET Core Session Middleware.
Gebruikers kunnen zich beschermen tegen CSRF-beveiligingsproblemen door voorzorgsmaatregelen te nemen:
- Meld u af bij web-apps wanneer u klaar bent met het gebruik ervan.
- Wis regelmatig browsercookies.
CSRF-beveiligingsproblemen zijn echter fundamenteel een probleem met de web-app, niet de eindgebruiker.
Basisprincipes van verificatie
Cookie-gebaseerde verificatie is een populaire vorm van verificatie. Verificatiesystemen op basis van tokens worden steeds populairder, met name voor SPA's (Single Page Applications).
verificatie op basis van Cookie
Wanneer een gebruiker zich verifieert met behulp van zijn gebruikersnaam en wachtwoord, wordt er een token uitgegeven met een verificatieticket dat kan worden gebruikt voor verificatie en autorisatie. Het token wordt opgeslagen als een cookie die wordt verzonden bij elke aanvraag die de client doet. Het genereren en valideren van deze cookie wordt uitgevoerd door de Cookie Authentication Middleware. De middleware serialiseert een gebruikersprincipe in een versleutelde cookie. Bij volgende aanvragen valideert de middleware de cookie, creëert de principal opnieuw en wijst de principal toe aan de eigenschap HttpContext.User.
Verificatie op basis van tokens
Wanneer een gebruiker wordt geverifieerd, wordt er een token uitgegeven (geen antiforgery-token). Het token bevat gebruikersgegevens in de vorm van claims of een verwijzingstoken dat de app verwijst naar de gebruikersstatus die in de app wordt onderhouden. Wanneer een gebruiker probeert toegang te krijgen tot een resource waarvoor verificatie is vereist, wordt het token verzonden naar de app met een extra autorisatieheader in de vorm van een Bearer-token. Deze aanpak maakt de app staatloos. In elke volgende aanvraag wordt het token doorgegeven in de aanvraag voor validatie aan de serverzijde. Dit token is niet versleuteld; het is gecodeerd. Op de server wordt het token gedecodeerd om toegang te krijgen tot de gegevens. Als u het token wilt verzenden voor volgende aanvragen, slaat u het token op in de lokale opslag van de browser. Wees niet bezorgd over CSRF-beveiligingsproblemen als het token is opgeslagen in de lokale opslag van de browser. CSRF is een probleem wanneer het token wordt opgeslagen in een cookie. Raadpleeg voor meer informatie het GitHub-issue SPA-codevoorbeeld voegt twee cookies toe.
Meerdere apps die worden gehost in één domein
Gedeelde hostingomgevingen zijn kwetsbaar voor sessiekaaking, aanmeldings-CSRF en andere aanvallen.
Hoewel example1.contoso.net
en example2.contoso.net
verschillende hosts zijn, is er een impliciete vertrouwensrelatie tussen hosts onder het *.contoso.net
domein. Met deze impliciete vertrouwensrelatie kunnen mogelijk niet-vertrouwde hosts de cookies van elkaar beïnvloeden (hetzelfde origin-beleid dat AJAX-aanvragen regelt, zijn niet noodzakelijkerwijs van toepassing op HTTP-cookies).
Aanvallen die gebruikmaken van vertrouwde cookies tussen apps die in hetzelfde domein worden gehost, kunnen worden voorkomen door geen domeinen te delen. Wanneer elke app wordt gehost in een eigen domein, is er geen impliciete cookie vertrouwensrelatie om misbruik te maken.
Antiforgery in ASP.NET Core
Waarschuwing
ASP.NET Core implementeert antivervalsing met behulp van ASP.NET Core Data Protection-. De gegevensbeveiligingsstack moet zijn geconfigureerd voor gebruik in een serverfarm. Zie Gegevensbeveiliging configurerenvoor meer informatie.
Antiforgery-middleware wordt toegevoegd aan de Dependency Injection container wanneer een van de volgende API's wordt aangeroepen in Program.cs
:
De FormTagHelper- voegt antiforgery-tokens toe aan HTML-formulierelementen. Met de volgende markeringen in een Razor-bestand worden automatisch antivervalsingstokens gegenereerd:
<form method="post">
<!-- ... -->
</form>
Op dezelfde manier genereert IHtmlHelper.BeginForm standaard antivervalsingstokens als de methode van het formulier niet GET is.
De automatische generatie van antivervalsingstokens voor HTML-formulierelementen vindt plaats wanneer de tag <form>
het kenmerk method="post"
bevat en een van de volgende waar is:
- Het actiekenmerk is leeg (
action=""
). - Het actiekenmerk wordt niet opgegeven (
<form method="post">
).
Het automatisch genereren van antivervalsingstokens voor HTML-formulierelementen kan worden uitgeschakeld:
Schakel antivervalsingstokens expliciet uit met het kenmerk
asp-antiforgery
:<form method="post" asp-antiforgery="false"> <!-- ... --> </form>
Het formulierelement wordt afgemeld voor Tag Helpers met behulp van de Tag Helper ! opt-out symbool:
<!form method="post"> <!-- ... --> </!form>
Verwijder de
FormTagHelper
uit de weergave. DeFormTagHelper
kan uit een weergave worden verwijderd door de volgende instructie toe te voegen aan de Razor weergave:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Notitie
De Razor pagina's worden automatisch beveiligd tegen XSRF/CSRF. Zie XSRF/CSRF en Razor Pagesvoor meer informatie.
De meest voorkomende benadering voor het verdedigen van CSRF-aanvallen is het gebruik van de Synchroontokenpatroon (STP). STP wordt gebruikt wanneer de gebruiker een pagina aanvraagt met formuliergegevens:
- De server verzendt een token dat is gekoppeld aan de identity van de huidige gebruiker naar de client.
- De client stuurt het token terug naar de server voor verificatie.
- Als de server een token ontvangt dat niet overeenkomt met de identityvan de geverifieerde gebruiker, wordt de aanvraag geweigerd.
Het token is uniek en onvoorspelbaar. Het token kan ook worden gebruikt om de juiste volgorde van een reeks aanvragen te garanderen (bijvoorbeeld om ervoor te zorgen dat de aanvraagvolgorde van: pagina 1 > pagina 2 > pagina 3). Alle formulieren in ASP.NET Core MVC- en Razor Pages-sjablonen genereren antivervalsingstokens. Met het volgende paar weergavevoorbeelden worden antivervalsingstokens gegenereerd:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Voeg expliciet een antivervalsingstoken toe aan een <form>
-element zonder Tag Helpers te gebruiken met de HTML-helper @Html.AntiForgeryToken
:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
In elk van de voorgaande gevallen voegt ASP.NET Core een verborgen formulierveld toe dat vergelijkbaar is met het volgende voorbeeld:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core bevat drie filters voor het werken met antivervalsingstokens:
Antivervalsing met behulp van AddControllers
Het aanroepen van AddControllersschakelt geen antivervalsingstokens in. AddControllersWithViews moet worden aangeroepen om ingebouwde antivervalsingstokenondersteuning aan te bieden.
Meerdere browsertabbladen en het Synchronizertokenpatroon
Met het synchronisatiepatroon bevat alleen de laatst geladen pagina een geldig antiforgery-token. Het gebruik van meerdere tabbladen kan problematisch zijn. Als een gebruiker bijvoorbeeld meerdere tabbladen opent:
- Alleen het laatst geladen tabblad bevat een geldig antiforgery-token.
- Aanvragen van eerder geladen tabbladen mislukken met een fout:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Overweeg alternatieve CSRF-beveiligingspatronen als dit een probleem vormt.
Antiforgery configureren met AntiforgeryOptions
AntiforgeryOptions aanpassen in Program.cs
:
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Stel de antivervalsingseigenschappen Cookie
in met behulp van de eigenschappen van de klasse CookieBuilder, zoals wordt weergegeven in de volgende tabel.
Optie | Beschrijving |
---|---|
Cookie | Bepaalt de instellingen die worden gebruikt om de antivervalsing-cookies te maken. |
FormFieldName | De naam van het verborgen formulierveld dat wordt gebruikt door het antivervalsingssysteem om antiforgerytokens weer te geven in weergaven. |
HeaderName | De naam van de header die wordt gebruikt door het antivervalsingssysteem. Wanneer null het geval is, beschouwt het systeem alleen formuliergegevens. |
SuppressXFrameOptionsHeader | Hiermee geeft u op of het genereren van de X-Frame-Options header moet worden onderdrukt. De header wordt standaard gegenereerd met de waarde SAMEORIGIN. Standaard ingesteld op false . |
Zie CookieAuthenticationOptionsvoor meer informatie.
Antivervalsingstokens genereren met IAntiforgery
IAntiforgery biedt de API voor het configureren van antivervalsingfuncties.
IAntiforgery
kan worden aangevraagd in Program.cs
met behulp van WebApplication.Services. In het volgende voorbeeld wordt middleware van de home-pagina van de app gebruikt om een antiforgery-token te genereren en het als een cookiein het antwoord te verzenden:
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);
});
In het voorgaande voorbeeld wordt een cookie met de naam XSRF-TOKEN
ingesteld. De client kan deze cookie lezen en de waarde ervan opgeven als een header die is gekoppeld aan AJAX-aanvragen. Angular bevat bijvoorbeeld ingebouwde XSRF-beveiliging die standaard een cookie met de naam XSRF-TOKEN
leest.
Antivervalsingsvalidatie vereisen
Het ValidateAntiForgeryToken actiefilter kan worden toegepast op een afzonderlijke actie, een controller of globaal. Aanvragen voor acties waarop dit filter is toegepast, worden geblokkeerd, tenzij de aanvraag een geldig antiforgery-token bevat:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Het kenmerk ValidateAntiForgeryToken
vereist een token voor aanvragen naar de actiemethoden die worden gemarkeerd, inclusief HTTP GET-aanvragen. Als het kenmerk ValidateAntiForgeryToken
wordt toegepast op de controllers van de app, kan dit worden overschreven met het kenmerk IgnoreAntiforgeryToken
.
Antiforgery-tokens alleen automatisch valideren voor onveilige HTTP-methoden
In plaats van het kenmerk ValidateAntiForgeryToken
breed toe te passen en dit vervolgens te overschrijven met IgnoreAntiforgeryToken
kenmerken, kan het kenmerk AutoValidateAntiforgeryToken worden gebruikt. Dit kenmerk werkt identiek aan het kenmerk ValidateAntiForgeryToken
, behalve dat er geen tokens nodig zijn voor aanvragen die zijn gedaan met behulp van de volgende HTTP-methoden:
- TOEVOEGEN
- HOOFD
- OPTIES
- SPOOR
U wordt aangeraden AutoValidateAntiforgeryToken
breed te gebruiken voor niet-API-scenario's. Dit kenmerk zorgt ervoor dat POST-acties standaard worden beveiligd. Het alternatief is om antivervalsingstokens standaard te negeren, tenzij ValidateAntiForgeryToken
wordt toegepast op afzonderlijke actiemethoden. In dit scenario is het waarschijnlijker dat een POST-actiemethode per ongeluk onbeveiligd blijft, waardoor de app kwetsbaar blijft voor CSRF-aanvallen. Alle POST's moeten het antivervalsingstoken verzenden.
API's hebben geen automatisch mechanisme voor het verzenden van het niet-cookie deel van het token. De implementatie is waarschijnlijk afhankelijk van de implementatie van de clientcode. Hieronder ziet u enkele voorbeelden:
Voorbeeld op klasseniveau:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Globaal voorbeeld:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Antiforgery-kenmerken van globale of controller overschrijven
Het IgnoreAntiforgeryToken filter wordt gebruikt om de noodzaak van een antiforgery-token voor een bepaalde actie (of controller) te elimineren. Wanneer dit filter wordt toegepast, overschrijft dit filter ValidateAntiForgeryToken
en AutoValidateAntiforgeryToken
filters die zijn opgegeven op een hoger niveau (globaal of op een controller).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Tokens vernieuwen na verificatie
Tokens moeten worden vernieuwd nadat de gebruiker is geverifieerd door de gebruiker te leiden naar een weergave of Razor pagina.
JavaScript, AJAX en SPAs
In traditionele HTML-apps worden antivervalsingstokens doorgegeven aan de server met behulp van verborgen formuliervelden. In moderne op JavaScript gebaseerde apps en SPA's worden veel aanvragen programmatisch gedaan. Deze AJAX-aanvragen kunnen andere technieken (zoals aanvraagheaders of cookies) gebruiken om het token te verzenden.
Als cookies worden gebruikt om verificatietokens op te slaan en API-aanvragen op de server te verifiëren, is CSRF een potentieel probleem. Als lokale opslag wordt gebruikt om het token op te slaan, kan het csrf-beveiligingsprobleem worden beperkt omdat waarden van lokale opslag niet automatisch met elke aanvraag naar de server worden verzonden. Het gebruik van lokale opslag voor het opslaan van het antiforgery-token op de client en het verzenden van het token als aanvraagheader is een aanbevolen benadering.
JavaScript
Met behulp van JavaScript met views kan het token worden gemaakt met behulp van een service vanuit de view. Injecteer de IAntiforgery-service in de weergave en roep GetAndStoreTokensaan:
@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>
}
In het voorgaande voorbeeld wordt JavaScript gebruikt om de verborgen veldwaarde voor de AJAX POST-header te lezen.
Deze aanpak elimineert de noodzaak om rechtstreeks om te gaan met het instellen van cookies van de server of het lezen van deze cookies van de client. Wanneer het injecteren van de IAntiforgery-service echter niet mogelijk is, kan JavaScript via een extra aanvraag naar de server (meestal same-origin
) toegang krijgen tot een token in cookies. Vervolgens kan de inhoud van de cookieworden gebruikt om een header te maken met de waarde van het token.
Ervan uitgaande dat het script het token verzendt in een aanvraagheader met de naam X-XSRF-TOKEN
, configureert u de antiforgery-service om te zoeken naar de X-XSRF-TOKEN
-header:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
In het volgende voorbeeld wordt een beveiligd eindpunt toegevoegd waarmee het aanvraagtoken wordt geschreven naar een javaScript-leesbare 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();
In het volgende voorbeeld wordt JavaScript gebruikt om een AJAX-aanvraag te maken om het token te verkrijgen en een andere aanvraag te doen met de juiste header:
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}`
}
Windows-verificatie en antivervalsingscookies
Wanneer u Windows-verificatie gebruikt, moeten toepassingseindpunten worden beveiligd tegen CSRF-aanvallen op dezelfde manier als voor cookies. De browser verzendt impliciet de verificatiecontext naar de server en daarom moeten eindpunten worden beveiligd tegen CSRF-aanvallen.
Antiforgery uitbreiden
Met het type IAntiforgeryAdditionalDataProvider kunnen ontwikkelaars het gedrag van het anti-CSRF-systeem uitbreiden door extra gegevens in elk token uit te wisselen. De methode GetAdditionalData wordt aangeroepen telkens wanneer een veldtoken wordt gegenereerd en de retourwaarde wordt ingesloten in het gegenereerde token. Een implementeerfunctie kan een tijdstempel, een nonce of een andere waarde retourneren en vervolgens ValidateAdditionalData aanroepen om deze gegevens te valideren wanneer het token wordt gevalideerd. De gebruikersnaam van de client is al ingesloten in de gegenereerde tokens, dus u hoeft deze informatie niet op te nemen. Als een token aanvullende gegevens bevat, maar geen IAntiForgeryAdditionalDataProvider
is geconfigureerd, worden de aanvullende gegevens niet gevalideerd.
Aanvullende informatiebronnen
Cross-site request forgery (ook wel bekend als XSRF of CSRF) is een aanval op web-gehoste apps waarbij een schadelijke web-app invloed kan hebben op de interactie tussen een clientbrowser en een web-app die die browser vertrouwt. Deze aanvallen zijn mogelijk omdat webbrowsers bepaalde typen verificatietokens automatisch verzenden met elke aanvraag naar een website. Deze vorm van misbruik wordt ook wel een aanval met één klik genoemd of sessierijden omdat de aanval gebruikmaakt van de eerder geverifieerde sessie van de gebruiker.
Een voorbeeld van een CSRF-aanval:
Een gebruiker meldt zich aan bij
www.good-banking-site.example.com
met formulierverificatie. De server verifieert de gebruiker en geeft een antwoord met een verificatie cookie. De site is kwetsbaar voor aanvallen omdat deze een aanvraag vertrouwt die wordt ontvangen met een geldige authenticatie cookie.De gebruiker bezoekt een schadelijke site,
www.bad-crook-site.example.com
.De schadelijke site,
www.bad-crook-site.example.com
, bevat een HTML-formulier dat vergelijkbaar is met het volgende voorbeeld:<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>
U ziet dat het formulier met
action
naar de kwetsbare site wordt verzonden, niet naar de schadelijke site. Dit is het 'cross-site'-onderdeel van CSRF.De gebruiker selecteert de knop Verzenden. De browser doet de aanvraag en bevat automatisch de verificatie cookie voor het aangevraagde domein,
www.good-banking-site.example.com
.De aanvraag wordt uitgevoerd op de
www.good-banking-site.example.com
-server met de verificatiecontext van de gebruiker en kan elke actie uitvoeren die een geverifieerde gebruiker mag uitvoeren.
Naast het scenario waarin de gebruiker de knop selecteert om het formulier in te dienen, kan de schadelijke site:
- Voer een script uit waarmee het formulier automatisch wordt verzonden.
- Verzend de inzending van het formulier als een AJAX-aanvraag.
- Verberg het formulier met CSS.
Voor deze alternatieve scenario's is geen actie of invoer van de gebruiker vereist, behalve het aanvankelijk bezoeken van de schadelijke site.
Het gebruik van HTTPS voorkomt geen CSRF-aanval. De schadelijke site kan een https://www.good-banking-site.com/
aanvraag net zo eenvoudig verzenden als een onveilige aanvraag kan verzenden.
Sommige aanvallen richten zich op eindpunten die reageren op GET-aanvragen. In dat geval kan een afbeeldingstag worden gebruikt om de actie uit te voeren. Deze vorm van aanval is gebruikelijk op forumsites die afbeeldingen toestaan, maar JavaScript blokkeren. Apps die de status van GET-aanvragen wijzigen, waarbij variabelen of resources worden gewijzigd, zijn kwetsbaar voor schadelijke aanvallen. GET-aanvragen met een wijzigingsstatus zijn onveilig. Een best practice is om nooit de status van een GET-aanvraag te wijzigen.
CSRF-aanvallen zijn mogelijk tegen web-apps die cookies gebruiken voor verificatie, omdat:
- Browsers slaan cookies op die zijn uitgegeven door een web-app.
- Opgeslagen cookies omvatten sessiecookies voor geverifieerde gebruikers.
- Browsers verzenden alle cookies die zijn gekoppeld aan een domein naar de web-app, ongeacht hoe de aanvraag voor de app in de browser is gegenereerd.
CSRF-aanvallen zijn echter niet beperkt tot het misbruiken van cookies. Basis- en samenvattingsverificatie zijn bijvoorbeeld ook kwetsbaar. Nadat een gebruiker zich heeft aangemeld met Basis- of Digest-authenticatie, worden de referenties automatisch verzonden totdat de sessie eindigt.
In deze context verwijst sessie naar de sessie aan de clientzijde waarin de gebruiker wordt geverifieerd. Het is niet gerelateerd aan sessies aan de serverzijde of ASP.NET Core Session Middleware.
Gebruikers kunnen zich beschermen tegen CSRF-beveiligingsproblemen door voorzorgsmaatregelen te nemen:
- Meld u af bij web-apps wanneer u klaar bent met het gebruik ervan.
- Wis regelmatig browsercookies.
CSRF-beveiligingsproblemen zijn echter fundamenteel een probleem met de web-app, niet de eindgebruiker.
Basisprincipes van verificatie
Cookie-gebaseerde verificatie is een populaire vorm van verificatie. Verificatiesystemen op basis van tokens worden steeds populairder, met name voor SPA's (Single Page Applications).
verificatie op basis van Cookie
Wanneer een gebruiker zich verifieert met behulp van zijn gebruikersnaam en wachtwoord, wordt er een token uitgegeven met een verificatieticket dat kan worden gebruikt voor verificatie en autorisatie. Het token wordt opgeslagen als een cookie die wordt verzonden bij elke aanvraag die de client doet. Het genereren en valideren van deze cookie wordt uitgevoerd door de Cookie Authentication Middleware. De middleware serialiseert een gebruikersprincipe in een versleutelde cookie. Bij volgende aanvragen valideert de middleware de cookie, creëert de principal opnieuw en wijst de principal toe aan de eigenschap HttpContext.User.
Verificatie op basis van tokens
Wanneer een gebruiker wordt geverifieerd, wordt er een token uitgegeven (geen antiforgery-token). Het token bevat gebruikersgegevens in de vorm van claims of een verwijzingstoken dat de app verwijst naar de gebruikersstatus die in de app wordt onderhouden. Wanneer een gebruiker probeert toegang te krijgen tot een resource waarvoor verificatie is vereist, wordt het token verzonden naar de app met een extra autorisatieheader in de vorm van een Bearer-token. Deze aanpak maakt de app staatloos. In elke volgende aanvraag wordt het token doorgegeven in de aanvraag voor validatie aan de serverzijde. Dit token is niet versleuteld; het is gecodeerd. Op de server wordt het token gedecodeerd om toegang te krijgen tot de gegevens. Als u het token wilt verzenden voor volgende aanvragen, slaat u het token op in de lokale opslag van de browser. Wees niet bezorgd over CSRF-beveiligingsproblemen als het token is opgeslagen in de lokale opslag van de browser. CSRF is een probleem wanneer het token wordt opgeslagen in een cookie. Raadpleeg voor meer informatie het GitHub-issue SPA-codevoorbeeld voegt twee cookies toe.
Meerdere apps die worden gehost in één domein
Gedeelde hostingomgevingen zijn kwetsbaar voor sessiekaaking, aanmeldings-CSRF en andere aanvallen.
Hoewel example1.contoso.net
en example2.contoso.net
verschillende hosts zijn, is er een impliciete vertrouwensrelatie tussen hosts onder het *.contoso.net
domein. Met deze impliciete vertrouwensrelatie kunnen mogelijk niet-vertrouwde hosts de cookies van elkaar beïnvloeden (hetzelfde origin-beleid dat AJAX-aanvragen regelt, zijn niet noodzakelijkerwijs van toepassing op HTTP-cookies).
Aanvallen die gebruikmaken van vertrouwde cookies tussen apps die in hetzelfde domein worden gehost, kunnen worden voorkomen door geen domeinen te delen. Wanneer elke app wordt gehost in een eigen domein, is er geen impliciete cookie vertrouwensrelatie om misbruik te maken.
ASP.NET Core antiforgery-configuratie
Waarschuwing
ASP.NET Core implementeert antivervalsing met behulp van ASP.NET Core Data Protection-. De gegevensbeveiligingsstack moet zijn geconfigureerd voor gebruik in een serverfarm. Zie Gegevensbeveiliging configurerenvoor meer informatie.
Antiforgery-middleware wordt toegevoegd aan de Dependency Injection container wanneer een van de volgende API's wordt aangeroepen in Startup.ConfigureServices
:
In ASP.NET Core 2.0 of hoger injecteert de FormTagHelper- antivervalsingstokens in HTML-formulierelementen. Met de volgende markeringen in een Razor-bestand worden automatisch antivervalsingstokens gegenereerd:
<form method="post">
...
</form>
Op dezelfde manier genereert IHtmlHelper.BeginForm standaard antivervalsingstokens als de methode van het formulier niet GET is.
De automatische generatie van antivervalsingstokens voor HTML-formulierelementen vindt plaats wanneer de tag <form>
het kenmerk method="post"
bevat en een van de volgende waar is:
- Het actiekenmerk is leeg (
action=""
). - Het actiekenmerk wordt niet opgegeven (
<form method="post">
).
Het automatisch genereren van antivervalsingstokens voor HTML-formulierelementen kan worden uitgeschakeld:
Schakel antivervalsingstokens expliciet uit met het kenmerk
asp-antiforgery
:<form method="post" asp-antiforgery="false"> ... </form>
Het formulierelement wordt afgemeld voor Tag Helpers met behulp van de Tag Helper ! opt-out symbool:
<!form method="post"> ... </!form>
Verwijder de
FormTagHelper
uit de weergave. DeFormTagHelper
kan uit een weergave worden verwijderd door de volgende instructie toe te voegen aan de Razor weergave:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Notitie
De Razor pagina's worden automatisch beveiligd tegen XSRF/CSRF. Zie XSRF/CSRF en Razor Pagesvoor meer informatie.
De meest voorkomende benadering voor het verdedigen van CSRF-aanvallen is het gebruik van de Synchroontokenpatroon (STP). STP wordt gebruikt wanneer de gebruiker een pagina aanvraagt met formuliergegevens:
- De server verzendt een token dat is gekoppeld aan de identity van de huidige gebruiker naar de client.
- De client stuurt het token terug naar de server voor verificatie.
- Als de server een token ontvangt dat niet overeenkomt met de identityvan de geverifieerde gebruiker, wordt de aanvraag geweigerd.
Het token is uniek en onvoorspelbaar. Het token kan ook worden gebruikt om de juiste volgorde van een reeks aanvragen te garanderen (bijvoorbeeld om ervoor te zorgen dat de aanvraagvolgorde van: pagina 1 > pagina 2 > pagina 3). Alle formulieren in ASP.NET Core MVC- en Razor Pages-sjablonen genereren antivervalsingstokens. Met het volgende paar weergavevoorbeelden worden antivervalsingstokens gegenereerd:
<form asp-controller="Todo" asp-action="Create" method="post">
...
</form>
@using (Html.BeginForm("Create", "Todo"))
{
...
}
Voeg expliciet een antivervalsingstoken toe aan een <form>
-element zonder Tag Helpers te gebruiken met de HTML-helper @Html.AntiForgeryToken
:
<form action="/" method="post">
@Html.AntiForgeryToken()
</form>
In elk van de voorgaande gevallen voegt ASP.NET Core een verborgen formulierveld toe dat vergelijkbaar is met het volgende voorbeeld:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core bevat drie filters voor het werken met antivervalsingstokens:
Antiforgery-opties
AntiforgeryOptions aanpassen in Startup.ConfigureServices
:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Stel de antivervalsingseigenschappen Cookie
in met behulp van de eigenschappen van de klasse CookieBuilder, zoals wordt weergegeven in de volgende tabel.
Optie | Beschrijving |
---|---|
Cookie | Bepaalt de instellingen die worden gebruikt om de antivervalsing-cookies te maken. |
FormFieldName | De naam van het verborgen formulierveld dat wordt gebruikt door het antivervalsingssysteem om antiforgerytokens weer te geven in weergaven. |
HeaderName | De naam van de header die wordt gebruikt door het antivervalsingssysteem. Wanneer null het geval is, beschouwt het systeem alleen formuliergegevens. |
SuppressXFrameOptionsHeader | Hiermee geeft u op of het genereren van de X-Frame-Options header moet worden onderdrukt. De header wordt standaard gegenereerd met de waarde SAMEORIGIN. Standaard ingesteld op false . |
Zie CookieAuthenticationOptionsvoor meer informatie.
Antiforgery-functies configureren met IAntiforgery
IAntiforgery biedt de API voor het configureren van antivervalsingfuncties.
IAntiforgery
kan worden aangevraagd in de Configure
methode van de klasse Startup
.
In het volgende voorbeeld:
- Middleware van de home-pagina van de app wordt gebruikt om een antiforgery-token te genereren en dit als een cookiein het antwoord te verzenden.
- Het aanvraagtoken wordt verzonden als een javaScript-leesbare cookie met de standaardnaamconventie van Angular die wordt beschreven in de sectie 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);
});
}
Antivervalsingsvalidatie vereisen
ValidateAntiForgeryToken is een actiefilter dat kan worden toegepast op een afzonderlijke actie, een controller of globaal. Aanvragen die worden uitgevoerd op acties waarop dit filter is toegepast, worden geblokkeerd, tenzij de aanvraag een geldig antiforgery-token bevat.
[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 });
}
Het kenmerk ValidateAntiForgeryToken
vereist een token voor aanvragen naar de actiemethoden die worden gemarkeerd, inclusief HTTP GET-aanvragen. Als het kenmerk ValidateAntiForgeryToken
wordt toegepast op de controllers van de app, kan dit worden overschreven met het kenmerk IgnoreAntiforgeryToken
.
Notitie
ASP.NET Core biedt geen ondersteuning voor het automatisch toevoegen van antivervalsingstokens aan GET-aanvragen.
Antiforgery-tokens alleen automatisch valideren voor onveilige HTTP-methoden
ASP.NET Core-apps genereren geen antivervalsingstokens voor veilige HTTP-methoden (GET, HEAD, OPTIONS en TRACE). In plaats van het kenmerk ValidateAntiForgeryToken
breed toe te passen en dit vervolgens te overschrijven met IgnoreAntiforgeryToken
kenmerken, kan het kenmerk AutoValidateAntiforgeryToken worden gebruikt. Dit kenmerk werkt identiek aan het kenmerk ValidateAntiForgeryToken
, behalve dat er geen tokens nodig zijn voor aanvragen die zijn gedaan met behulp van de volgende HTTP-methoden:
- TOEVOEGEN
- HOOFD
- OPTIES
- SPOOR
U wordt aangeraden AutoValidateAntiforgeryToken
breed te gebruiken voor niet-API-scenario's. Dit kenmerk zorgt ervoor dat POST-acties standaard worden beveiligd. Het alternatief is om antivervalsingstokens standaard te negeren, tenzij ValidateAntiForgeryToken
wordt toegepast op afzonderlijke actiemethoden. In dit scenario is het waarschijnlijker dat een POST-actiemethode per ongeluk onbeveiligd blijft, waardoor de app kwetsbaar blijft voor CSRF-aanvallen. Alle POST's moeten het antivervalsingstoken verzenden.
API's hebben geen automatisch mechanisme voor het verzenden van het niet-cookie deel van het token. De implementatie is waarschijnlijk afhankelijk van de implementatie van de clientcode. Hieronder ziet u enkele voorbeelden:
Voorbeeld op klasseniveau:
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
Globaal voorbeeld:
services.AddControllersWithViews(options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));
Antiforgery-kenmerken van globale of controller overschrijven
Het IgnoreAntiforgeryToken filter wordt gebruikt om de noodzaak van een antiforgery-token voor een bepaalde actie (of controller) te elimineren. Wanneer dit filter wordt toegepast, overschrijft dit filter ValidateAntiForgeryToken
en AutoValidateAntiforgeryToken
filters die zijn opgegeven op een hoger niveau (globaal of op een controller).
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
{
// no antiforgery token required
}
}
Tokens vernieuwen na verificatie
Tokens moeten worden vernieuwd nadat de gebruiker is geverifieerd door de gebruiker te leiden naar een weergave of Razor pagina.
JavaScript, AJAX en SPAs
In traditionele HTML-apps worden antivervalsingstokens doorgegeven aan de server met behulp van verborgen formuliervelden. In moderne op JavaScript gebaseerde apps en SPA's worden veel aanvragen programmatisch gedaan. Deze AJAX-aanvragen kunnen andere technieken (zoals aanvraagheaders of cookies) gebruiken om het token te verzenden.
Als cookies worden gebruikt om verificatietokens op te slaan en API-aanvragen op de server te verifiëren, is CSRF een potentieel probleem. Als lokale opslag wordt gebruikt om het token op te slaan, kan het csrf-beveiligingsprobleem worden beperkt omdat waarden van lokale opslag niet automatisch met elke aanvraag naar de server worden verzonden. Het gebruik van lokale opslag voor het opslaan van het antiforgery-token op de client en het verzenden van het token als aanvraagheader is een aanbevolen benadering.
JavaScript
Met behulp van JavaScript met views kan het token worden gemaakt met behulp van een service vanuit de view. Injecteer de IAntiforgery-service in de weergave en roep GetAndStoreTokensaan:
@{
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>
Deze aanpak elimineert de noodzaak om rechtstreeks om te gaan met het instellen van cookies van de server of het lezen van deze cookies van de client.
In het voorgaande voorbeeld wordt JavaScript gebruikt om de verborgen veldwaarde voor de AJAX POST-header te lezen.
JavaScript heeft ook toegang tot tokens in cookies en gebruikt de inhoud van de cookieom een header te maken met de waarde van het token.
context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,
new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });
Ervan uitgaande dat het script vraagt om het token te versturen in een header genaamd X-CSRF-TOKEN
, configureer de antivervalsingsservice om te zoeken naar de header genaamd X-CSRF-TOKEN
.
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");
In het volgende voorbeeld wordt JavaScript gebruikt om een AJAX-aanvraag met de juiste header uit te voeren:
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 gebruikt een conventie om CSRF aan te pakken. Als de server een cookie met de naam XSRF-TOKEN
verzendt, voegt de service AngularJS $http
de cookie-waarde toe aan een header wanneer er een aanvraag naar de server wordt verzonden. Dit proces is automatisch. De client hoeft de header niet expliciet in te stellen. De naam van de header is X-XSRF-TOKEN
. De server moet deze header detecteren en de inhoud ervan valideren.
Voor ASP.NET Core-API om te werken met deze conventie in het opstarten van uw toepassing:
- Configureer uw app om een token op te geven in een cookie met de naam
XSRF-TOKEN
. - Configureer de antivervalsingsservice om te zoeken naar een header met de naam
X-XSRF-TOKEN
. Dit is de standaardheadernaam van Angular voor het verzenden van het XSRF-token.
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");
}
Notitie
Wanneer het antivervalsingstoken wordt opgegeven in zowel de verzoekheader als in de inhoud van het formulier, wordt alleen het token in de header gevalideerd.
Windows-verificatie en antivervalsingscookies
Wanneer u Windows-verificatie gebruikt, moeten toepassingseindpunten worden beveiligd tegen CSRF-aanvallen op dezelfde manier als voor cookies. De browser verzendt impliciet de verificatiecontext naar de server en daarom moeten eindpunten worden beveiligd tegen CSRF-aanvallen.
Antiforgery uitbreiden
Met het type IAntiforgeryAdditionalDataProvider kunnen ontwikkelaars het gedrag van het anti-CSRF-systeem uitbreiden door extra gegevens in elk token uit te wisselen. De methode GetAdditionalData wordt aangeroepen telkens wanneer een veldtoken wordt gegenereerd en de retourwaarde wordt ingesloten in het gegenereerde token. Een implementeerfunctie kan een tijdstempel, een nonce of een andere waarde retourneren en vervolgens ValidateAdditionalData aanroepen om deze gegevens te valideren wanneer het token wordt gevalideerd. De gebruikersnaam van de client is al ingesloten in de gegenereerde tokens, dus u hoeft deze informatie niet op te nemen. Als een token aanvullende gegevens bevat, maar geen IAntiForgeryAdditionalDataProvider
is geconfigureerd, worden de aanvullende gegevens niet gevalideerd.