Dela via


Förhindra XSRF-/CSRF-attacker (Cross-Site Request Forgery) i ASP.NET Core

Av Fiyaz Hasan och Rick Anderson

Förfalskning av begäranden mellan webbplatser är ett angrepp mot webbaserade appar där en skadlig webbapp kan påverka interaktionen mellan en klientwebbläsare och en webbapp som litar på webbläsaren. Dessa attacker är möjliga eftersom webbläsare skickar vissa typer av autentiseringstoken automatiskt med varje begäran till en webbplats. Den här typen av exploatering kallas även för en attack med ett klick eller session som körs eftersom attacken utnyttjar användarens tidigare autentiserade session. Förfalskning av begäranden mellan webbplatser kallas även XSRF eller CSRF.

Ett exempel på en CSRF-attack:

  1. En användare loggar in på www.good-banking-site.example.com med formulärautentisering. Servern autentiserar användaren och utfärdar ett svar som innehåller en autentisering cookie. Webbplatsen är sårbar för angrepp eftersom den litar på alla förfrågningar som den tar emot med en giltig autentisering cookie.

  2. Användaren besöker en skadlig webbplats www.bad-crook-site.example.com.

    Den skadliga webbplatsen, www.bad-crook-site.example.com, innehåller ett HTML-formulär som liknar följande exempel:

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

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

  3. Användaren väljer knappen Skicka. Webbläsaren gör begäran och innehåller automatiskt autentiseringen cookie för den begärda domänen www.good-banking-site.example.com.

  4. Begäran körs på www.good-banking-site.example.com-servern med användarens autentiseringskontext och kan utföra alla åtgärder som en autentiserad användare tillåts utföra.

Förutom scenariot där användaren väljer knappen för att skicka formuläret kan den skadliga webbplatsen:

  • Kör ett skript som automatiskt skickar formuläret.
  • Skicka formuläret som en AJAX-begäran.
  • Dölj formuläret med hjälp av CSS.

Dessa alternativa scenarier kräver ingen åtgärd eller indata från användaren förutom att först besöka den skadliga webbplatsen.

Att använda HTTPS förhindrar inte en CSRF-attack. Den skadliga webbplatsen kan skicka en https://www.good-banking-site.com/ begäran så enkelt som den kan skicka en osäker begäran.

Vissa attacker, anger mot slutpunkter som svarar på GET-begäranden, i så fall kan en img-tagg användas för att utföra åtgärden. Den här typen av angrepp är vanlig på forumwebbplatser som tillåter bilder men blockerar JavaScript. Appar som ändrar tillstånd för GET-begäranden, där variabler eller resurser ändras, är sårbara för skadliga attacker. GET-begäranden som ändrar tillstånd är osäkra. En bästa praxis är att aldrig ändra tillstånd för en GET-begäran.

CSRF-attacker är möjliga mot webbappar som använder cookies för autentisering eftersom:

  • Webbläsare lagrar cookies som utfärdats av en webbapp.
  • Lagrade cookies inkluderar sessionscookies för autentiserade användare.
  • Webbläsare skickar alla cookies som är associerade med en domän till webbappen varje begäran oavsett hur begäran till appen genererades i webbläsaren.

CSRF-attacker är dock inte begränsade till att utnyttja cookies. Till exempel är grundläggande och sammanfattad autentisering också sårbara. När en användare har loggat in med Basic- eller Digest-autentisering skickar webbläsaren automatiskt autentiseringsuppgifterna tills sessionen är slut.

I det här sammanhanget refererar session till den session på klientsidan som användaren autentiseras under. Det är inte relaterat till sessioner på serversidan eller ASP.NET Core Session Middleware.

Användare kan skydda mot CSRF-sårbarheter genom att vidta försiktighetsåtgärder:

  • Logga ut från webbappar när du är klar med att använda dem.
  • Rensa webbläsarcookies med jämna mellanrum.

CsRF-sårbarheter är dock i grunden ett problem med webbappen, inte slutanvändaren.

Grunderna för autentisering

Cookie-baserad autentisering är en populär form av autentisering. Tokenbaserade autentiseringssystem växer i popularitet, särskilt för ensidesprogram (SPA).

När en användare autentiserar med sitt användarnamn och lösenord utfärdas en token som innehåller en autentiseringsbiljett. Token kan användas för autentisering och auktorisering. Token lagras som en cookie som skickas med varje begäran som klienten gör. Generering och validering av den här cookie utförs med mellanprogrammet för Cookie-autentisering. mellanprogram serialiserar ett användarhuvudnamn till en krypterad cookie. Vid efterföljande begäranden validerar mellanprogrammet cookie, återskapar principalen och tilldelar principalen till egenskapen HttpContext.User.

Tokenbaserad autentisering

När en användare autentiseras utfärdas en token (inte en antiforgery-token). Tokenet innehåller användarinformation i form av anspråk eller en referenstoken som pekar appen mot användartillståndet som underhålls i appen. När en användare försöker komma åt en resurs som kräver autentisering skickas en token till appen med en extra auktoriseringsheader i form av en bearertoken. Den här metoden gör appen tillståndslös. I varje efterföljande begäran skickas token i begäran om verifiering på serversidan. Den här token är inte krypterad; det är kodat. På servern avkodas token för att komma åt informationen. Om du vill skicka token på efterföljande begäranden lagrar du token i webbläsarens lokala lagring. Att placera en token i webbläsarens lokala lagring och hämta den och använda den som en ägartoken ger skydd mot CSRF-attacker. Men om appen skulle vara sårbar för skriptinmatning via XSS eller en komprometterad extern JavaScript-fil kan en cyberattacker hämta valfritt värde från lokal lagring och skicka det till sig själva. ASP.NET Core kodar alla utdata på serversidan från variabler som standard, vilket minskar risken för XSS. Om du åsidosätter det här beteendet med hjälp av Html.Raw- eller anpassad kod med ej betrodda indata kan du öka risken för XSS.

Oroa dig inte för CSRF-sårbarhet om token lagras i webbläsarens lokala lagring. CSRF är ett problem när token lagras i en cookie. Mer information finns i GitHub-problemet SPA-kodexempel lägger till två cookies.

Flera appar som finns i en domän

Delade värdmiljöer är sårbara för sessionskapning, CSRF vid inloggning och andra attacker.

Även om example1.contoso.net och example2.contoso.net är olika värdar finns det en implicit förtroenderelation mellan värdar under den *.contoso.net domänen. Den här implicita förtroenderelationen gör att potentiellt ej betrodda värdar kan påverka varandras cookies (principerna för samma ursprung som styr AJAX-begäranden gäller inte nödvändigtvis för HTTP-cookies).

Attacker som utnyttjar betrodda cookies mellan appar som finns på samma domän kan förhindras genom att inte dela domäner. När varje app finns på sin egen domän finns det ingen implicit cookie förtroenderelation att utnyttja.

Antiforgery i ASP.NET Core

Varning

ASP.NET Core använder ASP.NET Core Data Protectionför att implementera skydd mot förfalskning. Dataskyddsstacken måste konfigureras för att fungera i en servergrupp. Mer information finns i Konfigurera dataskydd.

Antiforgery-mellanprogram läggs till i containern Dependency injection när något av följande API:er anropas i Program.cs:

Mer information finns i Antiforgery med minimala API:er.

FormTagHelper infogar antiforgery-token i HTML-formulärelement. Följande kod i en Razor-fil genererar automatiskt antiforgery-token:

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

På samma sätt genererar IHtmlHelper.BeginForm antiforgerytoken som standard om formulärets metod inte är GET.

Den automatiska genereringen av antiforgery-token för HTML-formulärelement sker när taggen <form> innehåller attributet method="post" och något av följande är sant:

  • Åtgärdsattributet är tomt (action="").
  • Åtgärdsattributet anges inte (<form method="post">).

Automatisk generering av antiforgery-token för HTML-formulärelement kan inaktiveras:

  • Avaktivera antifalsifieringstoken uttryckligen med attributet asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Formulärelementet väljs bort från Tag Helpers genom att använda Tag Helper ! opt-out-symbolen:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Ta bort FormTagHelper från vyn. Du kan ta bort FormTagHelper från en vy genom att lägga till följande direktiv i vyn Razor:

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

Obs

Razor Pages skyddas automatiskt från XSRF/CSRF. Mer information finns i XSRF/CSRF och Razor Pages.

Den vanligaste metoden för att skydda mot CSRF-attacker är att använda synkroniserartokens mönster (STP). STP används när användaren begär en sida med formulärdata:

  1. Servern skickar en token som är associerad med den aktuella användarens identity till klienten.
  2. Klienten skickar tillbaka token till servern för verifiering.
  3. Om servern tar emot en token som inte matchar den autentiserade användarens identityavvisas begäran.

Token är unik och oförutsägbar. Token kan också användas för att säkerställa korrekt sekvensering av en serie begäranden (till exempel genom att säkerställa begärandesekvensen på sidan 1 > sida 2 > sida 3). Alla formulär i ASP.NET Core MVC- och Razor Pages-mallar genererar antiforgery-token. Följande par av vyexempel genererar anti-förfalskningstecken:

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

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

Lägg till en antiforgery-token uttryckligen i ett <form>-element utan att använda Tag Helpers med HTML-hjälparen @Html.AntiForgeryToken:

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

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

I vart och ett av de föregående fallen lägger ASP.NET Core till ett dolt formulärfält som liknar följande exempel:

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

ASP.NET Core innehåller tre filter för arbete med antiförfalsknings-token:

Antiforgery med AddControllers

Att anropa AddControllers gör inte att antiförfalskningsmarkörer aktiveras. AddControllersWithViews måste anropas för att ha inbyggt stöd för antiförfalskningstoken.

Flera webbläsarflikar och mönstret för synkroniseringstoken

Med mönstret Synkroniserar-token är det bara den senast inlästa sidan som garanterat innehåller en giltig förfalskningsskyddstoken. Appar som vill stödja flera flikar bör testa stöttade webbläsare och logga eventuella fel. Att använda flera flikar kan vara problematiskt. Om en användare till exempel öppnar flera flikar kan begäranden från tidigare inlästa flikar misslyckas med ett fel: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Överväg alternativa CSRF-skyddsmönster om detta utgör ett problem.

Konfigurera antiforgery med AntiforgeryOptions

Anpassa AntiforgeryOptions i Program.cs:

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

Ange egenskaper för förfalskningsskydd Cookie med hjälp av egenskaperna för klassen CookieBuilder, som du ser i följande tabell.

Alternativ Beskrivning
Cookie Avgör vilka inställningar som används för att skapa antiforgery-cookies.
FormFieldName Namnet på det gömda formulärfältet som används av antiforgery-systemet för att generera antiforgery-tokens i vyer.
HeaderName Namnet på rubriken som används av antiforgerysystemet. Om nulltar systemet endast hänsyn till formulärdata.
SuppressXFrameOptionsHeader Anger om du vill utelämna genereringen av X-Frame-Options-huvudet. Som standard genereras rubriken med värdet "SAMEORIGIN". Standardvärdet är false.

Mer information finns i CookieAuthenticationOptions.

Generera tokens för skydd mot förfalskning med IAntiforgery

IAntiforgery tillhandahåller API:et för att konfigurera funktioner för skydd mot förfalskning. IAntiforgery kan begäras i Program.cs med hjälp av WebApplication.Services. I följande exempel används mellanprogramvara från appens home-sida för att generera en autenticitetstoken och skicka den i svaret som en cookie.

app.UseRouting();

app.UseAuthorization();

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

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

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

    return next(context);
});

I föregående exempel anges en cookie med namnet XSRF-TOKEN. Klienten kan läsa den här cookie och ange dess värde som en rubrik som är kopplad till AJAX-begäranden. Till exempel innehåller Angular inbyggt XSRF-skydd som läser en cookie med namnet XSRF-TOKEN som standard.

Kräv validering för att förhindra förfalskning

ValidateAntiForgeryToken åtgärdsfiltret kan tillämpas på en enskild åtgärd, en kontroller eller globalt. Begäranden som görs till åtgärder som har det här filtret tillämpade blockeras om inte begäran innehåller en giltig antiforgery-token:

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

    return RedirectToAction();
}

Attributet ValidateAntiForgeryToken kräver en token för begäranden till de åtgärdsmetoder som markeras, inklusive HTTP GET-begäranden. Om attributet ValidateAntiForgeryToken tillämpas på appens kontrollanter kan det åsidosättas med attributet IgnoreAntiforgeryToken.

Verifiera antiforgeringstoken automatiskt endast för osäkra HTTP-metoder

Istället för att använda attributet ValidateAntiForgeryToken på ett omfattande sätt och sedan åsidosätta det med IgnoreAntiforgeryToken-attributet, kan attributet AutoValidateAntiforgeryToken användas. Det här attributet fungerar identiskt med attributet ValidateAntiForgeryToken, förutom att det inte kräver token för begäranden som görs med hjälp av följande HTTP-metoder:

  • HUVUD
  • ALTERNATIV
  • SPÅRA

Vi rekommenderar att du använder AutoValidateAntiforgeryToken brett för scenarier som inte är API-scenarier. Det här attributet säkerställer att POST-åtgärder skyddas som standard. Alternativet är att ignorera antiforgery-token som standard, såvida inte ValidateAntiForgeryToken tillämpas på enskilda åtgärdsmetoder. I det här scenariot är det mer troligt att en POST-åtgärdsmetod lämnas oskyddad av misstag, vilket gör appen sårbar för CSRF-attacker. Alla POST:er bör skicka antiforgery-token.

API:er har ingen automatisk mekanism för att skicka den icke-cookie delen av token. Implementeringen beror förmodligen på klientkodimplementeringen. Några exempel visas nedan:

Exempel på klassnivå:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Globalt exempel:

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

Åsidosätt globala attribut eller kontrollantens antiforgery-attribut

Filtret IgnoreAntiforgeryToken används för att eliminera behovet av en antiforgerytoken för en viss åtgärd (eller kontroller). När det här filtret används åsidosätter det ValidateAntiForgeryToken- och AutoValidateAntiforgeryToken-filter som anges på en högre nivå (globalt eller på en kontrollenhet).

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

    return RedirectToAction();
}

Uppdatera token efter autentisering

Token bör uppdateras efter att användaren har autentiserats genom att omdirigera användaren till en vy eller Razor Pages-sidan.

JavaScript, AJAX och SPA

I traditionella HTML-baserade appar skickas antiforgerytoken till servern med hjälp av dolda formulärfält. I moderna JavaScript-baserade appar och SPA:er görs många begäranden programmatiskt. Dessa AJAX-begäranden kan använda andra tekniker, till exempel begärandehuvuden eller cookies, för att skicka token.

Om cookies används för att lagra autentiseringstoken och autentisera API-begäranden på servern är CSRF ett potentiellt problem. Om lokal lagring används för att lagra token kan säkerhetsrisken för CSRF minskas eftersom värden från lokal lagring inte skickas automatiskt till servern med varje begäran. Användning av lokal lagring för att spara antiförfalskningstoken på klienten och skicka tokenen som en begäranderubrik är en rekommenderad metod.

Blazor

Mer information finns i ASP.NET Core Blazor-autentisering och auktorisering.

JavaScript

När man använder JavaScript med vyer kan en token skapas med hjälp av en tjänst inifrån vyn. Mata in IAntiforgery-tjänsten i vyn och anropa GetAndStoreTokens:

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

I föregående exempel används JavaScript för att läsa det dolda fältvärdet för AJAX POST-huvudet.

Den här metoden eliminerar behovet av att hantera att ange cookies direkt från servern eller läsa dem från klienten. Men när det inte går att injicera IAntiforgery-tjänsten, använd JavaScript för att komma åt token i cookies.

  • Åtkomsttoken i en ytterligare begäran till servern, vanligtvis same-origin.
  • Använd innehållet i cookieför att skapa en rubrik med tokens värde.

Om skriptet skickar token i ett begärandehuvud med namnet X-XSRF-TOKENkonfigurerar du tjänsten för förfalskningsbekämpning för att leta efter X-XSRF-TOKEN-huvudet:

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

I följande exempel läggs en skyddad slutpunkt till som skriver en begärandetoken till en för JavaScript läsbar 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();

I följande exempel används JavaScript för att göra en AJAX-begäran för att hämta token och göra en annan begäran med rätt rubrik:

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

Anteckning

När anti-förfalsknings-token anges i både begärandehuvudet och i formulärets nyttolast verifieras endast tokenen i begärandehuvudet.

Antiforgery med minimala API:er

Anropa AddAntiforgery och UseAntiforgery(IApplicationBuilder) för att registrera tjänster för förfalskningsskydd i DI. Antiforgery-token används för att minimera förfalskningsattacker mellan webbplatser.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

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

app.Run();

Antiforgery-mellanprogrammet:

Antiforgery-token verifieras endast om:

  • Slutpunkten innehåller metadata som implementerar IAntiforgeryMetadata där RequiresValidation=true.
  • HTTP-metoden som är associerad med slutpunkten är en relevant HTTP-metod. De relevanta metoderna är alla HTTP-metoder förutom TRACE, OPTIONS, HEAD och GET.
  • Begäran är associerad med en giltig slutpunkt.

Obs! När det är aktiverat manuellt måste mellanprogrammet för skydd mot förfalskning köras efter mellanprogrammet för autentisering och auktorisering för att förhindra att formulärdata läsas när användaren är oautentiserad.

Som standard kräver minimala API:er som accepterar formulärdata verifiering av antiforgery-token.

Överväg följande GenerateForm metod:

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

Föregående kod har tre argument, åtgärden, antiforgery-token och en bool som anger om token ska användas.

Tänk på följande exempel:

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

I föregående kod publicerar du till:

  • /todo kräver en giltig förfalskningsskyddstoken.
  • /todo2 kräver inte en giltig antiförfalskningstoken eftersom DisableAntiforgery anropas.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

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

Ett inlägg till:

  • /todo från formuläret som genereras av slutpunkten / lyckas eftersom förfalskningsskyddstoken är giltig.
  • /todo från formuläret som genereras av /SkipToken misslyckas eftersom anti-förfalskningsmekanismen inte ingår.
  • /todo2 från formuläret som genereras av /DisableAntiforgery-ändpunkten lyckas eftersom förfalskningsskydd inte krävs.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

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

När ett formulär skickas utan en giltig säkerhetskod:

  • I utvecklingsmiljön kastas ett undantag.
  • I produktionsmiljön loggas ett meddelande.

Windows-autentisering och förfalskningsskyddande cookies

När du använder Windows-autentisering måste programslutpunkter skyddas mot CSRF-attacker på samma sätt som för cookies. Webbläsaren skickar implicit autentiseringskontexten till servern och slutpunkterna måste skyddas mot CSRF-attacker.

Utöka förfalskningsskydd

Med IAntiforgeryAdditionalDataProvider-typen kan utvecklare utöka beteendet för anti-CSRF-systemet genom att skicka ytterligare data fram och tillbaka med varje token. Metoden GetAdditionalData anropas varje gång en fälttoken genereras och returvärdet bäddas in i den genererade token. En implementer kan returnera en tidsstämpel, en nonce eller något annat värde och sedan anropa ValidateAdditionalData för att verifiera dessa data när token verifieras. Klientens användarnamn är redan inbäddat i de genererade token, så du behöver inte inkludera den här informationen. Om en token innehåller kompletterande data men ingen IAntiForgeryAdditionalDataProvider har konfigurerats verifieras inte tilläggsdata.

Ytterligare resurser

Förfalskning av begäranden mellan webbplatser (även kallat XSRF eller CSRF) är en attack mot webbaserade appar där en skadlig webbapp kan påverka interaktionen mellan en klientwebbläsare och en webbapp som litar på webbläsaren. Dessa attacker är möjliga eftersom webbläsare skickar vissa typer av autentiseringstoken automatiskt med varje begäran till en webbplats. Den här typen av exploat kallas även för en en-klicksattack eller session riding eftersom attacken utnyttjar användarens tidigare autentiserade session.

Ett exempel på en CSRF-attack:

  1. En användare loggar in på www.good-banking-site.example.com med formulärautentisering. Servern autentiserar användaren och utfärdar ett svar som innehåller en autentisering cookie. Webbplatsen är sårbar för angrepp eftersom den litar på alla förfrågningar som den tar emot med en giltig autentisering cookie.

  2. Användaren besöker en skadlig webbplats www.bad-crook-site.example.com.

    Den skadliga webbplatsen, www.bad-crook-site.example.com, innehåller ett HTML-formulär som liknar följande exempel:

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

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

  3. Användaren väljer knappen Skicka. Webbläsaren gör begäran och innehåller automatiskt autentiseringen cookie för den begärda domänen www.good-banking-site.example.com.

  4. Begäran körs på www.good-banking-site.example.com-servern med användarens autentiseringskontext och kan utföra alla åtgärder som en autentiserad användare tillåts utföra.

Förutom scenariot där användaren väljer knappen för att skicka formuläret kan den skadliga webbplatsen:

  • Kör ett skript som automatiskt skickar formuläret.
  • Skicka formuläret som en AJAX-begäran.
  • Dölj formuläret med hjälp av CSS.

Dessa alternativa scenarier kräver ingen åtgärd eller indata från användaren förutom att först besöka den skadliga webbplatsen.

Att använda HTTPS förhindrar inte en CSRF-attack. Den skadliga webbplatsen kan skicka en https://www.good-banking-site.com/ begäran lika enkelt som den kan skicka en osäker begäran.

Vissa attacker riktar sig mot slutpunkter som svarar på GET-begäranden, då kan en img-tagg användas för att utföra åtgärden. Den här typen av angrepp är vanlig på forumwebbplatser som tillåter bilder men blockerar JavaScript. Appar som ändrar tillstånd för GET-begäranden, där variabler eller resurser ändras, är sårbara för skadliga attacker. GET-begäranden som ändrar tillstånd är osäkra. Bästa praxis är att aldrig ändra tillstånd för en GET-förfrågan.

CSRF-attacker är möjliga mot webbappar som använder cookies för autentisering eftersom:

  • Webbläsare lagrar cookies som utfärdats av en webbapp.
  • Lagrade cookies inkluderar sessionscookies för autentiserade användare.
  • Webbläsare skickar alla cookies som är associerade med en domän till webbappen varje begäran oavsett hur begäran till appen genererades i webbläsaren.

CSRF-attacker är dock inte begränsade till att utnyttja cookies. Till exempel är grundläggande och sammanfattad autentisering också sårbara. När en användare har loggat in med Basic- eller Digest-autentisering skickar webbläsaren automatiskt autentiseringsuppgifterna tills sessionen är slut.

I det här sammanhanget refererar session till den session på klientsidan som användaren autentiseras under. Det är inte relaterat till sessioner på serversidan eller ASP.NET Core Session Middleware.

Användare kan skydda mot CSRF-sårbarheter genom att vidta försiktighetsåtgärder:

  • Logga ut från webbappar när du är klar med att använda dem.
  • Rensa webbläsarcookies med jämna mellanrum.

CsRF-sårbarheter är dock i grunden ett problem med webbappen, inte slutanvändaren.

Grunderna för autentisering

Cookie-baserad autentisering är en populär form av autentisering. Tokenbaserade autentiseringssystem växer i popularitet, särskilt för ensidesprogram (SPA).

När en användare autentiserar med sitt användarnamn och lösenord utfärdas en token som innehåller en autentiseringsbiljett som kan användas för autentisering och auktorisering. Token lagras som en cookie som skickas med varje begäran som klienten gör. Generering och validering av den här cookie utförs av Cookie Authentication Middleware. mellanprogram serialiserar ett användarhuvudnamn till en krypterad cookie. Vid efterföljande begäranden validerar mellanprogrammet cookie, återskapar huvudnamnet och tilldelar huvudnamnet till egenskapen HttpContext.User.

Tokenbaserad autentisering

När en användare autentiseras utfärdas en token (inte en antiforgery-token). Ett token innehåller användarinformation i form av anspråk eller en referenstoken som pekar appen mot det användartillstånd som appen underhåller. När en användare försöker komma åt en resurs som kräver autentisering skickas tokens till appen med ett extra autentiseringshuvud i form av en bearer-token. Den här metoden gör appen tillståndslös. I varje efterföljande begäran skickas token i begäran om verifiering på serversidan. Den här token är inte krypterad; det är kodat. På servern avkodas token för att komma åt informationen. Om du vill skicka token på efterföljande begäranden lagrar du token i webbläsarens lokala lagring. Att placera en token i webbläsarens lokala lagring och hämta den och använda den som en ägartoken ger skydd mot CSRF-attacker. Men om appen skulle vara sårbar för skriptinmatning via XSS eller en komprometterad extern javascript-fil kan en cyberattacker hämta valfritt värde från lokal lagring och skicka det till sig själva. ASP.NET Core kodar alla utdata på serversidan från variabler som standard, vilket minskar risken för XSS. Om du åsidosätter det här beteendet med hjälp av Html.Raw- eller anpassad kod med ej betrodda indata kan du öka risken för XSS.

Oroa dig inte för CSRF-sårbarhet om token lagras i webbläsarens lokala lagring. CSRF är ett problem när token lagras i en cookie. Mer information finns i GitHub-problemet SPA-kodexempel lägger till två cookies.

Flera appar som finns i en domän

Delade värdmiljöer är sårbara för sessionskapning, inloggnings-CSRF och andra attacker.

Även om example1.contoso.net och example2.contoso.net är olika värdar finns det en implicit förtroenderelation mellan värdar under den *.contoso.net domänen. Den här implicita förtroenderelationen gör att potentiellt ej betrodda värdar kan påverka varandras cookies (principerna för samma ursprung som styr AJAX-begäranden gäller inte nödvändigtvis för HTTP-cookies).

Attacker som utnyttjar betrodda cookies mellan appar som finns på samma domän kan förhindras genom att inte dela domäner. När varje app finns på sin egen domän finns det ingen implicit cookie förtroenderelation att utnyttja.

Antiforgery i ASP.NET Core

Varning

ASP.NET Core implementerar förfalskningsskydd med ASP.NET Core Data Protection. Dataskyddsstacken måste konfigureras för att fungera i en servergrupp. Mer information finns i Konfigurera dataskydd.

Antiforgery-mellanprogram läggs till i containern Dependency injection när något av följande API:er anropas i Program.cs:

FormTagHelper infogar antiforgery-token i HTML-formulärelementen. Följande kod i en Razor-fil genererar automatiskt antiforgery-token:

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

På samma sätt genererar IHtmlHelper.BeginForm antiforgerytoken som standard om formulärets metod inte är GET.

Den automatiska genereringen av antiforgery-token för HTML-formulärelement sker när taggen <form> innehåller attributet method="post" och något av följande är sant:

  • Åtgärdsattributet är tomt (action="").
  • Åtgärdsattributet anges inte (<form method="post">).

Automatisk generering av antiforgery-token för HTML-formulärelement kan inaktiveras:

  • Inaktivera uttryckligen antiforgery-tokenen med attributet asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Formulärelementet utesluts från Tag Helpers med hjälp av Tag Helper-! opt-out-symbolen:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Ta bort FormTagHelper från vyn. Du kan ta bort FormTagHelper från en vy genom att lägga till följande direktiv i vyn Razor:

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

Notera

Razor Pages är skyddade automatiskt från XSRF/CSRF. Mer information finns i XSRF/CSRF och Razor Pages.

Den vanligaste metoden för att försvara sig mot CSRF-attacker är att använda Synkroniserartokens mönster (STP). STP används när användaren begär en sida med formulärdata:

  1. Servern skickar en token som är associerad med den aktuella användarens identity till klienten.
  2. Klienten skickar tillbaka token till servern för verifiering.
  3. Om servern tar emot en token som inte matchar den autentiserade användarens identityavvisas begäran.

Token är unik och oförutsägbar. Token kan också användas för att säkerställa korrekt sekvensering av en serie begäranden (till exempel genom att säkerställa begärandesekvensen på sidan 1 > sida 2 > sida 3). Alla formulär i ASP.NET Core MVC- och Razor Pages-mallar genererar antiforgery-token. Följande par vyexempel genererar antiförfalskningskoder:

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

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

Lägg uttryckligen till en antiförfalskningstoken i ett <form>-element utan att använda Tag Helpers med HTML-hjälparen @Html.AntiForgeryToken.

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

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

I vart och ett av de föregående fallen lägger ASP.NET Core till ett dolt formulärfält som liknar följande exempel:

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

ASP.NET Core innehåller tre filteren för att arbeta med antiförfalskningstokens:

Förfalskningsskydd med AddControllers

Att anropa AddControllersaktiverar inte antiförfalskningstoken. AddControllersWithViews måste anropas för att få inbyggt stöd för antiförfalskningssymbol.

Flera webbläsarflikar och mönstret för synkroniseringstoken

Med Synkroniserare token-mönstret innehåller endast den senast inlästa sidan en giltig antiförfalskningstoken. Det kan vara problematiskt att använda flera flikar. Om en användare till exempel öppnar flera flikar:

  • Endast den senast inlästa fliken innehåller en giltig antiforgery-token.
  • Begäranden från tidigare inlästa flikar misslyckas med ett fel: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Överväg alternativa CSRF-skyddsmönster om detta utgör ett problem.

Konfigurera antiförfalskning med AntiforgeryOptions

Anpassa AntiforgeryOptions i Program.cs:

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

Ange egenskaper för förfalskningsskydd Cookie med hjälp av egenskaperna för klassen CookieBuilder, som du ser i följande tabell.

Alternativ Beskrivning
Cookie Avgör vilka inställningar som används för att skapa antiforgery-cookies.
FormFieldName Namnet på det dolda formulärfält som används av antiforgery-systemet för att återge antiforgery-token i vyer.
HeaderName Namnet på rubriken som används av antiförfalskningssystemet. Om nulltar systemet endast hänsyn till formulärdata.
SuppressXFrameOptionsHeader Anger om du vill utelämna genereringen av X-Frame-Options-huvudet. Som standard genereras rubriken med värdet "SAMEORIGIN". Standardvärdet är false.

Mer information finns i CookieAuthenticationOptions.

Generera antiförfalskningstokens med IAntiforgery

IAntiforgery tillhandahåller API:et för att konfigurera antiförfalskningsfunktioner. IAntiforgery kan begäras i Program.cs med hjälp av WebApplication.Services. I följande exempel används mellanprogram från appens home-sida för att generera en antiforgery-token och skicka den i svaret som en cookie:

app.UseRouting();

app.UseAuthorization();

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

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

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

    return next(context);
});

I föregående exempel anges en cookie med namnet XSRF-TOKEN. Klienten kan läsa den här cookie och ange dess värde som en rubrik som är kopplad till AJAX-begäranden. Till exempel innehåller Angular inbyggt XSRF-skydd som läser en cookie med namnet XSRF-TOKEN som standard.

Kräv verifikation mot förfalskning

ValidateAntiForgeryToken åtgärdsfilter kan tillämpas på en enskild åtgärd, en kontroller eller globalt. Begäranden som görs till åtgärder som har det här filtret tillämpade blockeras om inte begäran innehåller en giltig antiforgery-token:

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

    return RedirectToAction();
}

Attributet ValidateAntiForgeryToken kräver en token för begäranden till de åtgärdsmetoder som markeras, inklusive HTTP GET-begäranden. Om attributet ValidateAntiForgeryToken tillämpas på appens kontrollanter kan det åsidosättas med attributet IgnoreAntiforgeryToken.

Verifiera antiforgeringstoken automatiskt endast för osäkra HTTP-metoder

I stället för att brett använda attributet ValidateAntiForgeryToken och sedan åsidosätta det med IgnoreAntiforgeryToken-attribut, kan attributet AutoValidateAntiforgeryToken användas. Det här attributet fungerar identiskt med attributet ValidateAntiForgeryToken, förutom att det inte kräver token för begäranden som görs med hjälp av följande HTTP-metoder:

  • HUVUD
  • ALTERNATIV
  • SPÅRA

Vi rekommenderar att du använder AutoValidateAntiforgeryToken brett för scenarier som inte är API-scenarier. Det här attributet säkerställer att POST-åtgärder skyddas som standard. Alternativet är att ignorera antiforgery-token som standard, såvida inte ValidateAntiForgeryToken tillämpas på enskilda åtgärdsmetoder. I det här scenariot är det mer troligt att en POST-åtgärdsmetod lämnas oskyddad av misstag, vilket gör appen sårbar för CSRF-attacker. Alla POST:er bör skicka antiforgery-token.

API:er har ingen automatisk mekanism för att skicka den icke-cookie delen av token. Implementeringen beror förmodligen på klientkodimplementeringen. Några exempel visas nedan:

Exempel på klassnivå:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Globalt exempel:

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

Åsidosätt globala attribut eller kontrollantens antiforgery-attribut

Filtret IgnoreAntiforgeryToken används för att ta bort behovet av en förfalskningsskyddstoken för en viss åtgärd (eller kontroller). När det här filtret används åsidosätter det filtrena ValidateAntiForgeryToken och AutoValidateAntiforgeryToken som anges på en högre nivå (globalt eller på en kontrollenhet).

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

    return RedirectToAction();
}

Uppdatera token efter autentisering

Tokenen bör uppdateras när användaren har autentiserats genom att omdirigera användaren till en vy eller Razor Pages-sida.

JavaScript, AJAX och SPA

I traditionella HTML-baserade appar skickas antiforgerytoken till servern med hjälp av dolda formulärfält. I moderna JavaScript-baserade appar och SPA:er görs många begäranden programmatiskt. Dessa AJAX-begäranden kan använda andra tekniker (till exempel begärandehuvuden eller cookies) för att skicka token.

Om cookies används för att lagra autentiseringstoken och autentisera API-begäranden på servern är CSRF ett potentiellt problem. Om lokal lagring används för att lagra token kan säkerhetsrisken för CSRF minskas eftersom värden från lokal lagring inte skickas automatiskt till servern med varje begäran. Att använda lokal lagring för att lagra antiforgery-token på klienten och skicka token som en begäranderubrik är en rekommenderad metod.

JavaScript

Med JavaScript med vyer kan token skapas med hjälp av en tjänst inifrån vyn. Mata in IAntiforgery-tjänsten i vyn och anropa GetAndStoreTokens:

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

I föregående exempel används JavaScript för att läsa det dolda fältvärdet för AJAX POST-huvudet.

Den här metoden eliminerar behovet av att hantera att ange cookies direkt från servern eller läsa dem från klienten. Men när det inte är möjligt att injicera IAntiforgery-tjänsten, kan du använda JavaScript för att komma åt tokens i cookies.

  • Åtkomsttokens i en ytterligare begäran till servern, typiskt vanligtvis same-origin.
  • Använd innehållet i cookieför att skapa en rubrik med tokens värde.

Om skriptet skickar token i ett begärandehuvud med namnet X-XSRF-TOKENkonfigurerar du tjänsten för förfalskningsbekämpning för att leta efter X-XSRF-TOKEN-huvudet:

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

I följande exempel läggs en skyddad slutpunkt som skriver begärandetoken till en JavaScript-läsbar 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();

I följande exempel används JavaScript för att göra en AJAX-begäran för att hämta token och göra en annan begäran med rätt rubrik:

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

Notera

När antiforgery-token anges i både begäran och i formulärdata verifieras endast token i begäran.

Antiförfalskning med minimal API:er

Minimal APIs stöder inte användningen av de inkluderade filtren (ValidateAntiForgeryToken, AutoValidateAntiforgeryToken, IgnoreAntiforgeryToken), men IAntiforgery tillhandahåller de API:er som krävs för att verifiera en begäran.

I följande exempel skapas ett filter som verifierar antiforgery-token:

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

        });
    }
}

Filtret kan sedan tillämpas på en slutpunkt:

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

Windows-autentisering och förfalskningsskydd-cookies

När du använder Windows-autentisering måste programslutpunkter skyddas mot CSRF-attacker på samma sätt som för cookies. Webbläsaren skickar implicit autentiseringskontexten till servern och slutpunkterna måste skyddas mot CSRF-attacker.

Utöka förfalskningsskydd

Med IAntiforgeryAdditionalDataProvider-typen kan utvecklare utöka beteendet för anti-CSRF-systemet genom att skicka ytterligare data fram och tillbaka i varje token. Metoden GetAdditionalData anropas varje gång en fälttoken genereras och returvärdet bäddas in i den genererade token. En implementer kan returnera en tidsstämpel, en nonce eller något annat värde och sedan anropa ValidateAdditionalData för att verifiera dessa data när token verifieras. Klientens användarnamn är redan inbäddat i de genererade token, så du behöver inte inkludera den här informationen. Om en token innehåller kompletterande data men ingen IAntiForgeryAdditionalDataProvider har konfigurerats verifieras inte tilläggsdata.

Ytterligare resurser

Förfalskning av begäranden mellan webbplatser (även kallat XSRF eller CSRF) är en attack mot webbaserade appar där en skadlig webbapp kan påverka interaktionen mellan en klientwebbläsare och en webbapp som litar på webbläsaren. Dessa attacker är möjliga eftersom webbläsare skickar vissa typer av autentiseringstoken automatiskt med varje begäran till en webbplats. Den här typen av exploatering kallas även för en one-click attack eller session riding eftersom attacken utnyttjar användarens tidigare autentiserade session.

Ett exempel på en CSRF-attack:

  1. En användare loggar in på www.good-banking-site.example.com med formulärautentisering. Servern autentiserar användaren och utfärdar ett svar som innehåller en autentisering cookie. Webbplatsen är sårbar för angrepp eftersom den litar på alla förfrågningar som den tar emot med en giltig autentisering cookie.

  2. Användaren besöker en skadlig webbplats www.bad-crook-site.example.com.

    Den skadliga webbplatsen, www.bad-crook-site.example.com, innehåller ett HTML-formulär som liknar följande exempel:

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

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

  3. Användaren väljer knappen Skicka. Webbläsaren gör begäran och innehåller automatiskt autentiseringen cookie för den begärda domänen www.good-banking-site.example.com.

  4. Begäran körs på www.good-banking-site.example.com-servern med användarens autentiseringskontext och kan utföra alla åtgärder som en autentiserad användare tillåts utföra.

Förutom scenariot där användaren väljer knappen för att skicka formuläret kan den skadliga webbplatsen:

  • Kör ett skript som automatiskt skickar formuläret.
  • Skicka formuläret som en AJAX-begäran.
  • Dölj formuläret med hjälp av CSS.

Dessa alternativa scenarier kräver ingen åtgärd eller indata från användaren förutom att först besöka den skadliga webbplatsen.

Att använda HTTPS förhindrar inte en CSRF-attack. Den skadliga webbplatsen kan skicka en https://www.good-banking-site.com/ begäran lika enkelt som den kan skicka en osäker begäran.

Vissa attacker riktar sig mot slutpunkter som är måltavlor och svarar på GET-begäranden, då kan en bildtagg användas för att åtgärden ska utföras. Den här typen av angrepp är vanlig på forumwebbplatser som tillåter bilder men blockerar JavaScript. Appar som ändrar tillstånd för GET-begäranden, där variabler eller resurser ändras, är sårbara för skadliga attacker. GET-förfrågningar som ändrar tillstånd är osäkra. En god praxis är att aldrig ändra tillstånd vid en GET-begäran.

CSRF-attacker är möjliga mot webbappar som använder cookies för autentisering eftersom:

  • Webbläsare lagrar cookies som utfärdats av en webbapp.
  • Lagrade cookies inkluderar sessionscookies för autentiserade användare.
  • Webbläsare skickar alla cookies som är associerade med en domän till webbappen varje begäran oavsett hur begäran till appen genererades i webbläsaren.

CSRF-attacker är dock inte begränsade till att utnyttja cookies. Till exempel är grundläggande och sammanfattad autentisering också sårbara. När en användare har loggat in med Basic- eller Digest-autentisering skickar webbläsaren automatiskt autentiseringsuppgifterna tills sessionen är slut.

I det här sammanhanget refererar session till den session på klientsidan som användaren autentiseras under. Det är inte relaterat till sessioner på serversidan eller ASP.NET Core Session Middleware.

Användare kan skydda mot CSRF-sårbarheter genom att vidta försiktighetsåtgärder:

  • Logga ut från webbappar när du är klar med att använda dem.
  • Rensa webbläsarcookies med jämna mellanrum.

CsRF-sårbarheter är dock i grunden ett problem med webbappen, inte slutanvändaren.

Grunderna för autentisering

Cookie-baserad autentisering är en populär form av autentisering. Tokenbaserade autentiseringssystem växer i popularitet, särskilt för ensidesprogram (SPA).

När en användare autentiserar med sitt användarnamn och lösenord utfärdas en token som innehåller en autentiseringsbiljett som kan användas för autentisering och auktorisering. Token lagras som en cookie som skickas med varje begäran som klienten gör. Generering och validering av den här cookie utförs av Cookie Authentication Middleware. mellanprogram serialiserar ett användarhuvudnamn till en krypterad cookie. Vid efterföljande begäranden validerar mellanprogrammet cookie, återskapar huvudnamnet och tilldelar huvudnamnet till egenskapen HttpContext.User.

Tokenbaserad autentisering

När en användare autentiseras utfärdas en token (inte en antiforgery-token). Tokenet innehåller användarinformation i form av anspråk eller en referenstoken som pekar appen till användartillståndet som underhålls i appen. När en användare försöker komma åt en resurs som kräver autentisering skickas en token till appen med en extra auktoriseringsrubrik i form av en bärartoken. Den här metoden gör appen tillståndslös. I varje efterföljande begäran skickas token i begäran om verifiering på serversidan. Den här token är inte krypterad; det är kodat. På servern avkodas token för att komma åt informationen. Om du vill skicka token på efterföljande begäranden lagrar du token i webbläsarens lokala lagring. Oroa dig inte för CSRF-sårbarhet om token lagras i webbläsarens lokala lagring. CSRF är ett problem när token lagras i en cookie. Mer information finns i GitHub-problemet där SPA-kodexemplet lägger till två kakor.

Flera appar som finns i en domän

Delade värdmiljöer är sårbara för sessionskapning, CSRF-inloggning och andra attacker.

Även om example1.contoso.net och example2.contoso.net är olika värdar finns det en implicit förtroenderelation mellan värdar under den *.contoso.net domänen. Den här implicita förtroenderelationen gör att potentiellt ej betrodda värdar kan påverka varandras cookies (principerna för samma ursprung som styr AJAX-begäranden gäller inte nödvändigtvis för HTTP-cookies).

Attacker som utnyttjar betrodda cookies mellan appar som finns på samma domän kan förhindras genom att inte dela domäner. När varje app finns på sin egen domän finns det ingen implicit cookie förtroenderelation att utnyttja.

Antiforgery i ASP.NET Core

Varning

ASP.NET Core implementerar antiforgery med ASP.NET Core Data Protection. Dataskyddsstacken måste konfigureras för att fungera i en servergrupp. Mer information finns i Konfigurera dataskydd.

Antiforgery-mellanprogram läggs till i containern Dependency injection när något av följande API:er anropas i Program.cs:

FormTagHelper infogar antiförfalskningsmarkörer i HTML-formulärelement. Följande kod i en Razor-fil genererar automatiskt antiforgery-token:

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

På samma sätt genererar IHtmlHelper.BeginForm antiforgerytoken som standard om formulärets metod inte är GET.

Den automatiska genereringen av antiforgery-token för HTML-formulärelement sker när taggen <form> innehåller attributet method="post" och något av följande är sant:

  • Åtgärdsattributet är tomt (action="").
  • Åtgärdsattributet anges inte (<form method="post">).

Automatisk generering av antiforgery-token för HTML-formulärelement kan inaktiveras:

  • Inaktivera antiforgery-token explicit med attributet asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Formulärelementet väljs bort från Tag Helpers genom att använda Tag Helper -! opt-out-symbolen:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Ta bort FormTagHelper från vyn. Du kan ta bort FormTagHelper från en vy genom att lägga till följande direktiv i vyn Razor:

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

Not

Razor Sidor skyddas automatiskt från XSRF/CSRF. Mer information finns i XSRF/CSRF och Razor Pages.

Den vanligaste metoden för att försvara sig mot CSRF-attacker är att använda Synkroniserartokens mönster (STP). STP används när användaren begär en sida med formulärdata:

  1. Servern skickar en token som är associerad med den aktuella användarens identity till klienten.
  2. Klienten skickar tillbaka token till servern för verifiering.
  3. Om servern tar emot en token som inte matchar den autentiserade användarens identityavvisas begäran.

Token är unik och oförutsägbar. Token kan också användas för att säkerställa korrekt sekvensering av en serie begäranden (till exempel genom att säkerställa begärandesekvensen på sidan 1 > sida 2 > sida 3). Alla formulär i ASP.NET Core MVC- och Razor Pages-mallar genererar antiforgery-token. Följande par exempel på vyer genererar antifalskningstokens:

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

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

Lägg uttryckligen till en antiforgerytoken i ett <form>-element utan att använda Tag Helpers med HTML-hjälparen @Html.AntiForgeryToken:

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

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

I vart och ett av de föregående fallen lägger ASP.NET Core till ett dolt formulärfält som liknar följande exempel:

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

ASP.NET Core innehåller tre filter för att arbeta med antiforgery-token:

Antiforgery med AddControllers

Att anropa AddControllersaktiverar inte antiförfalskningstoken. AddControllersWithViews måste anropas för att ha inbyggt stöd för antiförfalskningstoken.

Flera webbläsarflikar och mönstret för synkroniseringstoken

Med mönstret Synkroniserartoken innehåller endast den senast inlästa sidan en giltig antiforgery-token. Det kan vara problematiskt att använda flera flikar. Om en användare till exempel öppnar flera flikar:

  • Endast den senast inlästa fliken innehåller en giltig skyddstoken.
  • Begäranden från tidigare inlästa flikar misslyckas med ett fel: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Överväg alternativa CSRF-skyddsmönster om detta utgör ett problem.

Konfigurera antiforgery med AntiforgeryOptions

Anpassa AntiforgeryOptions i Program.cs:

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

Ange egenskaper för förfalskningsskydd Cookie med hjälp av egenskaperna för klassen CookieBuilder, som du ser i följande tabell.

Alternativ Beskrivning
Cookie Avgör vilka inställningar som används för att skapa antiforgery-cookies.
FormFieldName Namnet på det dolda formulärfält som används av systemet för bedrägeribekämpning för att generera bedrägeribekämpningstoken i vyerna.
HeaderName Namnet på huvudrubriken som används av systemet mot förfalskning. Om nulltar systemet endast hänsyn till formulärdata.
SuppressXFrameOptionsHeader Anger om du vill utelämna genereringen av X-Frame-Options-huvudet. Som standard genereras rubriken med värdet "SAMEORIGIN". Standardvärdet är false.

Mer information finns i CookieAuthenticationOptions.

Generera antiförfalskningstoken med IAntiforgery

IAntiforgery tillhandahåller API:et för att konfigurera skyddsfunktioner mot förfalskning. IAntiforgery kan begäras i Program.cs med hjälp av WebApplication.Services. I följande exempel används mellanprogram från appens home-sida för att generera en antiforgery-token och skicka den i svaret som en cookie:

app.UseRouting();

app.UseAuthorization();

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

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

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

    return next(context);
});

I föregående exempel definieras en cookie med namnet XSRF-TOKEN. Klienten kan läsa den här cookie och ange dess värde som en rubrik som är kopplad till AJAX-begäranden. Till exempel innehåller Angular inbyggt XSRF-skydd som läser en cookie med namnet XSRF-TOKEN som standard.

Kräv verifiering för att förhindra förfalskning

ValidateAntiForgeryToken åtgärdsfilter kan tillämpas på en enskild åtgärd, en kontroller eller globalt. Begäranden som görs till åtgärder som har det här filtret tillämpade blockeras om inte begäran innehåller en giltig antiforgery-token:

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

    return RedirectToAction();
}

Attributet ValidateAntiForgeryToken kräver en token för begäranden till de åtgärdsmetoder som markeras, inklusive HTTP GET-begäranden. Om attributet ValidateAntiForgeryToken tillämpas på appens kontrollanter kan det åsidosättas med attributet IgnoreAntiforgeryToken.

Verifiera antiforgeringstoken automatiskt endast för osäkra HTTP-metoder

I stället för att brett tillämpa attributet ValidateAntiForgeryToken och sedan skriva över det med IgnoreAntiforgeryToken-attribut, kan attributet AutoValidateAntiforgeryToken användas. Det här attributet fungerar identiskt med attributet ValidateAntiForgeryToken, förutom att det inte kräver token för begäranden som görs med hjälp av följande HTTP-metoder:

  • HUVUD
  • ALTERNATIV
  • SPÅRA

Vi rekommenderar att du använder AutoValidateAntiforgeryToken brett för scenarier som inte är API-scenarier. Det här attributet säkerställer att POST-åtgärder skyddas som standard. Alternativet är att ignorera antiforgery-token som standard, såvida inte ValidateAntiForgeryToken tillämpas på enskilda åtgärdsmetoder. I det här scenariot är det mer troligt att en POST-åtgärdsmetod lämnas oskyddad av misstag, vilket gör appen sårbar för CSRF-attacker. Alla POST:er bör skicka antiforgery-token.

API:er har ingen automatisk mekanism för att skicka den icke-cookie delen av token. Implementeringen beror förmodligen på klientkodimplementeringen. Några exempel visas nedan:

Exempel på klassnivå:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Globalt exempel:

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

Åsidosätt globala attribut eller kontrollantens antiforgery-attribut

Filtret IgnoreAntiforgeryToken används för att eliminera behovet av en antiforgery token för en viss åtgärd (eller kontroller). När det här filtret används åsidosätter det ValidateAntiForgeryToken- och AutoValidateAntiforgeryToken-filter som specificeras på högre nivå, globalt eller på en styrenhet.

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

    return RedirectToAction();
}

Uppdatera token efter autentisering

Tokens bör uppdateras efter att användaren har autentiserats genom att omdirigera användaren till en vy eller en Razor-sida.

JavaScript, AJAX och SPA

I traditionella HTML-baserade appar skickas antiforgerytoken till servern med hjälp av dolda formulärfält. I moderna JavaScript-baserade appar och SPA:er görs många begäranden programmatiskt. Dessa AJAX-begäranden kan använda andra tekniker (till exempel begärandehuvuden eller cookies) för att skicka token.

Om cookies används för att lagra autentiseringstoken och autentisera API-begäranden på servern är CSRF ett potentiellt problem. Om lokal lagring används för att lagra token kan säkerhetsrisken för CSRF minskas eftersom värden från lokal lagring inte skickas automatiskt till servern med varje begäran. Att använda lokalt minne för att spara antiforgery-token hos klienten och skicka token som en begäranderubrik är en rekommenderad metod.

JavaScript

När du använder JavaScript med vyer kan en token skapas med hjälp av en tjänst inifrån vyn. Mata in IAntiforgery-tjänsten i vyn och anropa GetAndStoreTokens:

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

I föregående exempel används JavaScript för att läsa det dolda fältvärdet för AJAX POST-huvudet.

Den här metoden eliminerar behovet av att hantera att ange cookies direkt från servern eller läsa dem från klienten. Men när det inte går att injicera IAntiforgery-tjänsten kan JavaScript också komma åt en token i cookies, som hämtas från en ytterligare begäran till servern (vanligtvis same-origin), och använda innehållet i cookieför att skapa ett huvud med tokenvärdet.

Om skriptet skickar token i ett begärandehuvud med namnet X-XSRF-TOKENkonfigurerar du tjänsten för förfalskningsbekämpning för att leta efter X-XSRF-TOKEN-huvudet:

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

I följande exempel lägger du till en skyddad slutpunkt som kommer att skriva begärandetoken till en JavaScript-läsbar 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();

I följande exempel används JavaScript för att göra en AJAX-begäran för att hämta token och göra en annan begäran med rätt rubrik:

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-autentisering och anti-förfalskningscookies

När du använder Windows-autentisering måste programslutpunkter skyddas mot CSRF-attacker på samma sätt som för cookies. Webbläsaren skickar implicit autentiseringskontexten till servern och därför måste slutpunkter skyddas mot CSRF-attacker.

Utöka förfalskningsskyddet

Med IAntiforgeryAdditionalDataProvider-typ kan utvecklare utöka beteendet för anti-CSRF-systemet genom att skicka ytterligare data fram och tillbaka i varje token. Metoden GetAdditionalData anropas varje gång en fälttoken genereras och returvärdet bäddas in i den genererade token. En implementer kan returnera en tidsstämpel, en nonce eller något annat värde och sedan anropa ValidateAdditionalData för att verifiera dessa data när token verifieras. Klientens användarnamn är redan inbäddat i de genererade token, så du behöver inte inkludera den här informationen. Om en token innehåller kompletterande data men ingen IAntiForgeryAdditionalDataProvider har konfigurerats verifieras inte tilläggsdata.

Ytterligare resurser

Förfalskning av begäranden mellan webbplatser (även kallat XSRF eller CSRF) är en attack mot webbaserade appar där en skadlig webbapp kan påverka interaktionen mellan en klientwebbläsare och en webbapp som litar på webbläsaren. Dessa attacker är möjliga eftersom webbläsare skickar vissa typer av autentiseringstoken automatiskt med varje begäran till en webbplats. Den här typen av exploatering kallas även för en attack med ett klick eller session som körs eftersom attacken utnyttjar användarens tidigare autentiserade session.

Ett exempel på en CSRF-attack:

  1. En användare loggar in på www.good-banking-site.example.com med formulärautentisering. Servern autentiserar användaren och utfärdar ett svar som innehåller en autentisering cookie. Webbplatsen är sårbar för angrepp eftersom den litar på alla förfrågningar som den tar emot med en giltig autentisering cookie.

  2. Användaren besöker en skadlig webbplats www.bad-crook-site.example.com.

    Den skadliga webbplatsen, www.bad-crook-site.example.com, innehåller ett HTML-formulär som liknar följande exempel:

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

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

  3. Användaren väljer knappen Skicka. Webbläsaren gör begäran och innehåller automatiskt autentiseringen cookie för den begärda domänen www.good-banking-site.example.com.

  4. Begäran körs på www.good-banking-site.example.com-servern med användarens autentiseringskontext och kan utföra alla åtgärder som en autentiserad användare tillåts utföra.

Förutom scenariot där användaren väljer knappen för att skicka formuläret kan den skadliga webbplatsen:

  • Kör ett skript som automatiskt skickar formuläret.
  • Skicka formuläret som en AJAX-begäran.
  • Dölj formuläret med hjälp av CSS.

Dessa alternativa scenarier kräver ingen åtgärd eller indata från användaren förutom att först besöka den skadliga webbplatsen.

Att använda HTTPS förhindrar inte en CSRF-attack. Den skadliga webbplatsen kan skicka en https://www.good-banking-site.com/ begäran lika enkelt som den kan skicka en osäker begäran.

Vissa attacker riktar sig mot ändpunkter som svarar på GET-begäranden, i sådana fall kan en bildtagg användas för att utföra åtgärden. Den här typen av angrepp är vanlig på forumwebbplatser som tillåter bilder men blockerar JavaScript. Appar som ändrar tillstånd för GET-begäranden, där variabler eller resurser ändras, är sårbara för skadliga attacker. GET-begäranden som ändrar tillstånd är osäkra. En bra praxis är att man aldrig bör ändra tillstånd vid en GET-begäran.

CSRF-attacker är möjliga mot webbappar som använder cookies för autentisering eftersom:

  • Webbläsare lagrar cookies som utfärdats av en webbapp.
  • Lagrade cookies inkluderar sessionscookies för autentiserade användare.
  • Webbläsare skickar alla cookies som är associerade med en domän till webbappen varje begäran oavsett hur begäran till appen genererades i webbläsaren.

CSRF-attacker är dock inte begränsade till att utnyttja cookies. Till exempel är grundläggande och sammanfattad autentisering också sårbara. När en användare har loggat in med Basic- eller Digest-autentisering skickar webbläsaren automatiskt autentiseringsuppgifterna tills sessionen är slut.

I det här sammanhanget refererar session till den session på klientsidan som användaren autentiseras under. Det är inte relaterat till sessioner på serversidan eller ASP.NET Core Session Middleware.

Användare kan skydda mot CSRF-sårbarheter genom att vidta försiktighetsåtgärder:

  • Logga ut från webbappar när du är klar med att använda dem.
  • Rensa webbläsarcookies med jämna mellanrum.

CsRF-sårbarheter är dock i grunden ett problem med webbappen, inte slutanvändaren.

Grunderna för autentisering

Cookie-baserad autentisering är en populär form av autentisering. Tokenbaserade autentiseringssystem växer i popularitet, särskilt för ensidesprogram (SPA).

När en användare autentiserar med sitt användarnamn och lösenord utfärdas en token som innehåller en autentiseringsbiljett som kan användas för autentisering och auktorisering. Token lagras som en cookie som skickas med varje begäran som klienten gör. Generering och validering av den här cookie utförs av Cookie Authentication Middleware. mellanprogram serialiserar ett användarhuvudnamn till en krypterad cookie. Vid efterföljande begäranden validerar mellanprogrammet cookie, återskapar huvudnamnet och tilldelar huvudnamnet till egenskapen HttpContext.User.

Tokenbaserad autentisering

När en användare autentiseras utfärdas en token (inte en antiforgery-token). Token innehåller användarinformation i form av anspråk eller en referenstoken som pekar appen mot användartillståndet som underhålls i appen. När en användare försöker komma åt en resurs som kräver autentisering skickas token till applikationen med ett extra auktoriseringshuvud i form av en bearertoken. Den här metoden gör appen tillståndslös. I varje efterföljande begäran skickas token i begäran om verifiering på serversidan. Den här token är inte krypterad; det är kodat. På servern avkodas token för att komma åt informationen. Om du vill skicka token på efterföljande begäranden lagrar du token i webbläsarens lokala lagring. Oroa dig inte för CSRF-sårbarhet om token lagras i webbläsarens lokala lagring. CSRF är ett problem när token lagras i en cookie. För mer information, se GitHub-ärendet där SPA-kodexemplet lägger till två cookies.

Flera appar som finns i en domän

Delade värdmiljöer är sårbara för sessionskapning, inloggnings-CSRF och andra attacker.

Även om example1.contoso.net och example2.contoso.net är olika värdar finns det en implicit förtroenderelation mellan värdar under den *.contoso.net domänen. Den här implicita förtroenderelationen gör att potentiellt ej betrodda värdar kan påverka varandras cookies (principerna för samma ursprung som styr AJAX-begäranden gäller inte nödvändigtvis för HTTP-cookies).

Attacker som utnyttjar betrodda cookies mellan appar som finns på samma domän kan förhindras genom att inte dela domäner. När varje app finns på sin egen domän finns det ingen implicit cookie förtroenderelation att utnyttja.

ASP.NET Core anti-förfalskningskonfiguration

Varning

ASP.NET Core genomför åtgärder mot förfalskning med ASP.NET Core Data Protection. Dataskyddsstacken måste konfigureras för att fungera i en servergrupp. Mer information finns i Konfigurera dataskydd.

Antiforgery-mellanprogram läggs till i containern Dependency injection när något av följande API:er anropas i Startup.ConfigureServices:

I ASP.NET Core 2.0 eller senare injicerar FormTagHelper antiforgery-tokenen i HTML-formulärelement. Följande kod i en Razor-fil genererar automatiskt antiforgery-token:

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

På samma sätt genererar IHtmlHelper.BeginForm antiforgerytoken som standard om formulärets metod inte är GET.

Den automatiska genereringen av antiforgery-token för HTML-formulärelement sker när taggen <form> innehåller attributet method="post" och något av följande är sant:

  • Åtgärdsattributet är tomt (action="").
  • Åtgärdsattributet anges inte (<form method="post">).

Automatisk generering av antiforgery-token för HTML-formulärelement kan inaktiveras:

  • Inaktivera uttryckligen antiförfalsknings-token med attributet asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • Formulärelementet avregistreras från Tag Helpers med hjälp av Tag Helper-! opt-out-symbol:

    <!form method="post">
        ...
    </!form>
    
  • Ta bort FormTagHelper från vyn. Du kan ta bort FormTagHelper från en vy genom att lägga till följande direktiv i vyn Razor:

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

Not

Razor Pages skyddas automatiskt från XSRF/CSRF. Mer information finns i XSRF/CSRF och Razor Pages.

Den vanligaste metoden för att försvara sig mot CSRF-attacker är att använda Synkroniserartokens mönster (STP). STP används när användaren begär en sida med formulärdata:

  1. Servern skickar en token som är associerad med den aktuella användarens identity till klienten.
  2. Klienten skickar tillbaka token till servern för verifiering.
  3. Om servern tar emot en token som inte matchar den autentiserade användarens identityavvisas begäran.

Token är unik och oförutsägbar. Token kan också användas för att säkerställa korrekt sekvensering av en serie begäranden (till exempel genom att säkerställa begärandesekvensen på sidan 1 > sida 2 > sida 3). Alla formulär i ASP.NET Core MVC- och Razor Pages-mallar genererar antiforgery-token. Följande par visningsexempel genererar förfalskningsskyddstoken:

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

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

Lägg uttryckligen till en antiforgery-token i ett <form>-element utan att använda Tag Helpers med HTML-hjälpen @Html.AntiForgeryToken:

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

I vart och ett av de föregående fallen lägger ASP.NET Core till ett dolt formulärfält som liknar följande exempel:

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

ASP.NET Core innehåller tre filter för att arbeta med antiforgery-token:

Alternativ för antiförfalskning

Anpassa AntiforgeryOptions i Startup.ConfigureServices:

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

Ange egenskaper för förfalskningsskydd Cookie med hjälp av egenskaperna för klassen CookieBuilder, som du ser i följande tabell.

Alternativ Beskrivning
Cookie Avgör vilka inställningar som används för att skapa antiforgery-cookies.
FormFieldName Namnet på det dolda formulärfält som används av antiforgery-systemet för att återge antiforgery-tokens i vyer.
HeaderName Namnet på rubriken som används av antiforgery-systemet. Om nulltar systemet endast hänsyn till formulärdata.
SuppressXFrameOptionsHeader Anger om du vill utelämna genereringen av X-Frame-Options-huvudet. Som standard genereras rubriken med värdet "SAMEORIGIN". Standardinställningen är false.

Mer information finns i CookieAuthenticationOptions.

Konfigurera förfalskningsskydd med IAntiforgery

IAntiforgery tillhandahåller API för att konfigurera antiförfalskningsfunktioner. IAntiforgery kan begäras i Configure-metoden för klassen Startup.

I följande exempel:

  • Middleware från appens home-sida används för att generera en antiförfalskningskod och skicka den i svaret som en cookie.
  • Begärandetoken skickas som en JavaScript-läsbar cookie med standardkonventionen för Angular-namngivning som beskrivs i avsnittet 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);
    });
}

Kräv verifiering av antiförfalskning

ValidateAntiForgeryToken är ett åtgärdsfilter som kan tillämpas på en enskild åtgärd, en kontrollant eller globalt. Begäranden som görs till åtgärder som har det här filtret tillämpade blockeras om inte begäran innehåller en giltig antiforgery-token.

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

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

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

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

Attributet ValidateAntiForgeryToken kräver en token för begäranden till de åtgärdsmetoder som markeras, inklusive HTTP GET-begäranden. Om attributet ValidateAntiForgeryToken tillämpas på appens kontrollanter kan det åsidosättas med attributet IgnoreAntiforgeryToken.

Note

ASP.NET Core stöder inte automatisk tillägg av antiforgery-token i GET-begäranden.

Verifiera antiforgeringstoken automatiskt endast för osäkra HTTP-metoder

ASP.NET Core-appar genererar inte antiforgerytoken för säkra HTTP-metoder (GET, HEAD, OPTIONS och TRACE). I stället för att brett tillämpa attributet ValidateAntiForgeryToken och sedan åsidosätta det med attributet IgnoreAntiforgeryToken, kan attributet AutoValidateAntiforgeryToken användas istället. Det här attributet fungerar identiskt med attributet ValidateAntiForgeryToken, förutom att det inte kräver token för begäranden som görs med hjälp av följande HTTP-metoder:

  • HÄMTA
  • HUVUD
  • ALTERNATIV
  • SPÅRA

Vi rekommenderar att du använder AutoValidateAntiforgeryToken brett för scenarier som inte är API-scenarier. Det här attributet säkerställer att POST-åtgärder skyddas som standard. Alternativet är att ignorera antiforgery-token som standard, såvida inte ValidateAntiForgeryToken tillämpas på enskilda åtgärdsmetoder. I det här scenariot är det mer troligt att en POST-åtgärdsmetod lämnas oskyddad av misstag, vilket gör appen sårbar för CSRF-attacker. Alla POST:er bör skicka antiforgery-token.

API:er har ingen automatisk mekanism för att skicka den icke-cookie delen av token. Implementeringen beror förmodligen på klientkodimplementeringen. Några exempel visas nedan:

Exempel på klassnivå:

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

Globalt exempel:

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

Åsidosätt globala attribut eller kontrollantens antiforgery-attribut

Filtret IgnoreAntiforgeryToken används för att ta bort behovet av en antiforgery-token för en specifik åtgärd (eller kontroller). När det här filtret används åsidosätter det filtren ValidateAntiForgeryToken och AutoValidateAntiforgeryToken som anges på en högre nivå (globalt eller på en kontroller).

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

Uppdatera token efter autentisering

Token bör uppdateras när användaren har autentiserats genom att omdirigera användaren till en vy eller Razor sida.

JavaScript, AJAX och SPA

I traditionella HTML-baserade appar skickas antiforgerytoken till servern med hjälp av dolda formulärfält. I moderna JavaScript-baserade appar och SPA:er görs många begäranden programmatiskt. Dessa AJAX-begäranden kan använda andra tekniker (till exempel begärandehuvuden eller cookies) för att skicka token.

Om cookies används för att lagra autentiseringstoken och autentisera API-begäranden på servern är CSRF ett potentiellt problem. Om lokal lagring används för att lagra token kan säkerhetsrisken för CSRF minskas eftersom värden från lokal lagring inte skickas automatiskt till servern med varje begäran. Att använda lokal lagring för att lagra antiforgery-token på klienten och skicka token som en begäranderubrik är en rekommenderad metod.

JavaScript

Genom att använda JavaScript med vyer kan ett token skapas med hjälp av en tjänst inom vyn. Mata in IAntiforgery-tjänsten i vyn och anropa GetAndStoreTokens:

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

Den här metoden eliminerar behovet av att hantera att ange cookies direkt från servern eller läsa dem från klienten.

I föregående exempel används JavaScript för att läsa det dolda fältvärdet för AJAX POST-huvudet.

JavaScript kan också komma åt token i cookies och använda innehållet i cookieför att skapa en rubrik med tokens värde.

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

Om du antar att skriptbegärandena om att skicka token i ett huvud med namnet X-CSRF-TOKEN, konfigurerar du tjänsten för förfalskningsbekämpning för att leta efter X-CSRF-TOKEN-huvudet:

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

I följande exempel används JavaScript för att göra en AJAX-begäran med rätt rubrik:

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 använder en konvention för att hantera CSRF. Om servern skickar en cookie med namnet XSRF-TOKENlägger tjänsten AngularJS $http till värdet cookie i ett huvud när en begäran skickas till servern. Den här processen är automatisk. Klienten behöver inte explicit ange rubriken. Rubriknamnet är X-XSRF-TOKEN. Servern bör identifiera det här huvud och verifiera innehållet.

För att ASP.NET Core-API:et ska fungera med den här konventionen i programstarten:

  • Konfigurera appen så att den anger en token i en cookie som heter XSRF-TOKEN.
  • Konfigurera antiforgery-tjänsten så att den söker efter en rubrik med namnet X-XSRF-TOKEN, som är Angulars standardhuvudnamn för att skicka 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");
}

Not

När antiforgery-tokens anges i både förfrågningshuvudet och i formulärets nyttolast valideras endast token i förfrågningshuvudet.

Windows-autentisering och antidatabedrägerikakor

När du använder Windows-autentisering måste programslutpunkter skyddas mot CSRF-attacker på samma sätt som för cookies. Webbläsaren skickar implicit autentiseringskontexten till servern och därför måste slutpunkter skyddas mot CSRF-attacker.

Utöka antiförfalskning

Med IAntiforgeryAdditionalDataProvider-typ möjliggörs det för utvecklare att utöka beteendet för anti-CSRF-systemet genom att medskicka ytterligare data i varje token. Metoden GetAdditionalData anropas varje gång en fälttoken genereras och returvärdet bäddas in i den genererade token. En implementer kan returnera en tidsstämpel, en nonce eller något annat värde och sedan anropa ValidateAdditionalData för att verifiera dessa data när token verifieras. Klientens användarnamn är redan inbäddat i de genererade token, så du behöver inte inkludera den här informationen. Om en token innehåller kompletterande data men ingen IAntiForgeryAdditionalDataProvider har konfigurerats verifieras inte tilläggsdata.

Ytterligare resurser