Udostępnij za pośrednictwem


Zapobieganie atakom fałszowania żądań między stronami (XSRF/CSRF) w ASP.NET Core

Przez Fiyaz Hasan i Rick Anderson

Fałszerzacja żądań między witrynami to atak na aplikacje hostowane w Internecie, w którym złośliwa aplikacja internetowa może wpływać na interakcję między przeglądarką klienta a aplikacją internetową, która ufa tej przeglądarce. Te ataki są możliwe, ponieważ przeglądarki internetowe automatycznie wysyłają niektóre typy tokenów uwierzytelniania z każdym żądaniem do witryny internetowej. Ta forma ataku jest również znana jako atak typu one-click lub atak session riding, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika. Fałszerstwo żądań między witrynami jest również znane jako XSRF lub CSRF.

Przykład ataku CSRF:

  1. Użytkownik loguje się do www.good-banking-site.example.com przy użyciu uwierzytelniania formularzy. Serwer uwierzytelnia użytkownika i wystawia odpowiedź zawierającą uwierzytelnianie cookie. Witryna jest podatna na ataki, ponieważ ufa wszelkim żądaniom otrzymanym przy użyciu prawidłowego uwierzytelniania cookie.

  2. Użytkownik odwiedza złośliwą witrynę. www.bad-crook-site.example.com

    Złośliwa witryna www.bad-crook-site.example.com, zawiera formularz HTML podobny do następującego przykładu:

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

    Zauważ, że formularz action wysyła dane do podatnej na zagrożenia witryny, a nie do złośliwej witryny. Jest to „międzystronowy” element CSRF.

  3. Użytkownik wybierze przycisk Prześlij. Przeglądarka wysyła żądanie i automatycznie dołącza uwierzytelnianie cookie dla żądanej domeny. www.good-banking-site.example.com

  4. Żądanie jest uruchamiane na www.good-banking-site.example.com serwerze z kontekstem uwierzytelniania użytkownika i może wykonać dowolną akcję, którą może wykonać uwierzytelniony użytkownik.

Oprócz scenariusza, w którym użytkownik wybiera przycisk do przesłania formularza, złośliwa witryna może:

  • Uruchom skrypt, który automatycznie przesyła formularz.
  • Wyślij formularz jako żądanie AJAX.
  • Ukryj formularz przy użyciu arkusza CSS.

Te alternatywne scenariusze nie wymagają żadnej akcji ani danych wejściowych od użytkownika innego niż początkowo odwiedzanie złośliwej witryny.

Korzystanie z protokołu HTTPS nie zapobiega atakowi CSRF. Złośliwa witryna może równie łatwo wysłać żądanie https://www.good-banking-site.example.com/, jak i niezabezpieczone żądanie.

Niektóre ataki są celem punktów końcowych, które odpowiadają na żądania GET, w takim przypadku tag obrazu może służyć do wykonania akcji. Ta forma ataku jest powszechna w witrynach forum, które zezwalają na obrazy, ale blokują język JavaScript. Aplikacje, które zmieniają stan żądań GET, w których zmieniane są zmienne lub zasoby, są narażone na złośliwe ataki. Żądania GET, które zmieniają stan, są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

Ataki CSRF są możliwe dla aplikacji internetowych, które używają plików cookie do uwierzytelniania, ponieważ:

  • Przeglądarki przechowują pliki cookie wystawione przez aplikację internetową.
  • Przechowywane pliki cookie obejmują pliki cookie sesji dla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie pliki cookie skojarzone z domeną do aplikacji internetowej, niezależnie od tego, jak żądanie do aplikacji zostało wygenerowane w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystywania plików cookie. Na przykład uwierzytelnianie podstawowe i Digest są również podatne. Po zalogowaniu się użytkownika przy użyciu uwierzytelniania podstawowego lub szyfrowego przeglądarka automatycznie wysyła poświadczenia do momentu zakończenia sesji.

W tym kontekście sesja odnosi się do sesji po stronie klienta, podczas której użytkownik jest uwierzytelniany. Nie ma to związku z sesjami po stronie serwera ani z ASP.NET Core Session Middleware.

Użytkownicy mogą chronić się przed lukami w zabezpieczeniach CSRF, stosując środki ostrożności:

  • Wyloguj się z aplikacji internetowych po zakończeniu korzystania z nich.
  • Okresowo usuwaj pliki cookie przeglądarki.

Jednak luki w zabezpieczeniach CSRF są zasadniczo problemem z aplikacją internetową, a nie użytkownikiem końcowym.

Podstawy uwierzytelniania

Cookie-oparte uwierzytelnianie jest popularne. Systemy uwierzytelniania oparte na tokenach rosną na popularności, szczególnie w przypadku aplikacji jednostronicowych (SPA).

Gdy użytkownik uwierzytelnia się przy użyciu nazwy użytkownika i hasła, wystawiony jest token zawierający bilet uwierzytelniania. Token może służyć do uwierzytelniania i autoryzacji. Token jest przechowywany jako cookie element, który jest wysyłany z każdym żądaniem wysyłanym przez klienta. Generowanie i weryfikowanie cookie odbywa się za pomocą oprogramowania pośredniczącego Cookie do uwierzytelniania. Oprogramowanie pośredniczące serializuje główną tożsamość użytkownika do zaszyfrowanego cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje element cookie, ponownie tworzy podmiot, i przypisuje podmiot do właściwości HttpContext.User.

Uwierzytelnianie oparte na tokenach

Po uwierzytelnieniu użytkownika otrzymuje token (a nie token antyforgery). Token zawiera informacje o użytkowniku w postaci oświadczeń lub tokenu referencyjnego wskazującego aplikację na stan użytkownika utrzymywany w aplikacji. Gdy użytkownik próbuje uzyskać dostęp do zasobu wymagającego uwierzytelnienia, token jest wysyłany do aplikacji z dodatkowym nagłówkiem autoryzacyjnym w postaci tokenu typu Bearer. Takie podejście sprawia, że aplikacja jest bezstanowa. W każdym kolejnym żądaniu token jest przekazywany w żądaniu weryfikacji po stronie serwera. Ten token nie jest zaszyfrowany; jest zakodowany. Na serwerze token jest dekodowany w celu uzyskania dostępu do informacji. Aby wysłać token do kolejnych żądań, zapisz token w magazynie lokalnym przeglądarki. Umieszczenie tokenu w magazynie lokalnym przeglądarki oraz jego pobranie i użycie jako tokenu nośnika zapewnia ochronę przed atakami CSRF. Jednak jeśli aplikacja jest podatna na wstrzyknięcie skryptu za pośrednictwem XSS lub naruszonego zewnętrznego pliku JavaScript, cyberattacker może pobrać dowolną wartość z magazynu lokalnego i wysłać ją do siebie. ASP.NET Core koduje domyślnie wszystkie dane wyjściowe po stronie serwera ze zmiennych, co zmniejsza ryzyko wystąpienia XSS. Jeśli to zachowanie zostanie zastąpione przy użyciu kodu Html.Raw lub niestandardowego z niezaufanymi danymi wejściowymi, może to spowodować zwiększenie ryzyka użycia usługi XSS.

Nie obawiaj się luki w zabezpieczeniach CSRF, jeśli token jest przechowywany w magazynie lokalnym przeglądarki. CSRF jest problemem, gdy token jest przechowywany w cookie. Aby uzyskać więcej informacji, zobacz zgłoszenie GitHub Przykładowy kod SPA dodaje dwa pliki cookie.

Wiele aplikacji hostowanych w jednej domenie

Środowiska hostingu współdzielonego są narażone na przejęcie sesji, logowanie CSRF i inne ataki.

Chociaż example1.contoso.net i example2.contoso.net są różnymi hostami, istnieje niejawna relacja zaufania między hostami w domenie *.contoso.net . Ta niejawna relacja zaufania pozwala potencjalnie niezaufanym hostom wpływać na pliki cookie innych (zasady tego samego źródła, które zarządzają żądaniami AJAX, nie muszą mieć zastosowania do plików cookie HTTP).

Ataki wykorzystujące zaufane pliki cookie między aplikacjami hostowanymi w tej samej domenie mogą być blokowane przez nieudostępnianie domen. Gdy każda aplikacja jest hostowana we własnej domenie, nie ma niejawnej cookie relacji zaufania do wykorzystania.

Ochrona przed fałszowaniem w ASP.NET Core

Ostrzeżenie

ASP.NET Core implementuje ochronę przed fałszerzją przy użyciu ASP.NET Core Data Protection. Stos ochrony danych musi być skonfigurowany do pracy w farmie serwerów. Aby uzyskać więcej informacji, zobacz Konfigurowanie ochrony danych.

Oprogramowanie pośredniczące chroniące przed fałszerzami jest dodawane do kontenera wstrzykiwania zależności, gdy jeden z następujących interfejsów API jest wywoływany w pliku Program.cs:

Aby uzyskać więcej informacji, zobacz Antiforgery with Minimal APIs.

Element FormTagHelper wprowadza tokeny chroniące przed fałszerstwem do elementów formularza HTML. Następujące znaczniki w Razor pliku automatycznie generują tokeny chroniące przed fałszerzami:

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

Podobnie, IHtmlHelper.BeginForm domyślnie generuje tokeny antyforgery, jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antywłamaniowych dla elementów formularza HTML ma miejsce, gdy tag <form> zawiera atrybut method="post" i spełniony jest jeden z następujących warunków:

  • Atrybut akcji jest pusty (action="").
  • Atrybut akcji nie jest podany (<form method="post">).

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML można wyłączyć:

  • Jawnie wyłącz tokeny ochrony przed fałszerzami za pomocą atrybutu asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Element formularza jest wyłączony z użycia Tag Helpers przy użyciu symbolu ! opt-out symbol.

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Usuń element FormTagHelper z widoku. Element FormTagHelper można usunąć z widoku, dodając następującą dyrektywę Razor do widoku:

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

Uwaga

Razor Strony są automatycznie chronione przed plikami XSRF/CSRF. Aby uzyskać więcej informacji, zobacz XSRF/CSRF i Razor Pages.

Najczęstszym podejściem do ochrony przed atakami CSRF jest użycie wzorca tokenu synchronizatora (STP). Usługa STP jest używana, gdy użytkownik żąda strony z danymi formularza:

  1. Serwer wysyła token skojarzony z tożsamością bieżącego użytkownika do klienta.
  2. Klient wysyła token z powrotem do serwera w celu weryfikacji.
  3. Jeśli serwer otrzyma token, który nie jest zgodny z tożsamością uwierzytelnionego użytkownika, żądanie zostanie odrzucone.

Token jest unikatowy i nieprzewidywalny. Token może również służyć do zapewnienia prawidłowego sekwencjonowania serii żądań (na przykład zapewnienia sekwencji żądań strony 1 > strona 2 > strona 3). Wszystkie formularze w szablonach ASP.NET Core MVC i Razor Pages generują tokeny antyforgery. Poniższa para przykładów widoków generuje tokeny chroniące przed fałszerzami:

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

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

Jawnie dodaj token antyforgery do elementu <form> bez używania pomocników tagów z pomocnikiem HTML @Html.AntiForgeryToken.

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

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

W każdym z powyższych przypadków ASP.NET Core dodaje ukryte pole formularza podobne do następującego przykładu:

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

ASP.NET Core zawiera trzy filtry do pracy z tokenami antyforgeryjnymi:

Zabezpieczenie przed fałszerstwem z AddControllers

Wywołanie AddControllers nie włącza tokenów antyfałszywych. AddControllersWithViews musi być wywoływany, aby zapewnić wbudowaną obsługę tokenów antyfałszerstwa.

Wiele kart przeglądarki i wzorzec tokenu synchronizatora

Wiele kart zalogowanych jako różni użytkownicy lub jedna zalogowana jako anonimowa nie są obsługiwane.

Konfigurowanie ochrony przed fałszerzją za pomocą polecenia AntiforgeryOptions

Dostosowywanie AntiforgeryOptions w programie Program.cs:

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

Ustaw właściwości ochrony przed fałszerzami Cookie przy użyciu właściwości CookieBuilder klasy, jak pokazano w poniższej tabeli.

Opcja Opis
Cookie Określa ustawienia używane do tworzenia plików cookie chroniących przed fałszerzami.
FormFieldName Nazwa pola ukrytego formularza używanego przez system antyforgery do renderowania tokenów antyforgeryjnych w widokach.
HeaderName Nazwa nagłówka używanego przez system anty-fałszywka. Jeśli nullsystem uwzględnia tylko dane formularza.
SuppressXFrameOptionsHeader Określa, czy pomijać generowanie nagłówka X-Frame-Options . Domyślnie nagłówek jest generowany z wartością "SAMEORIGIN". Wartość domyślna to false.

Aby uzyskać więcej informacji, zobacz CookieAuthenticationOptions.

Generowanie tokenów antyforgeryjnych za pomocą polecenia IAntiforgery

IAntiforgery udostępnia interfejs API do konfigurowania funkcji ochrony przed fałszerstwami. IAntiforgery można zażądać w Program.cs przy użyciu WebApplication.Services. W poniższym przykładzie użyto oprogramowania pośredniczącego ze strony głównej aplikacji do wygenerowania tokenu antyforgery i wysłania go w odpowiedzi jako cookie:

app.UseRouting();

app.UseAuthorization();

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

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

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

    return next(context);
});

Wcześniejszy przykład ustanawia cookie, które nazywa się XSRF-TOKEN. Klient może to cookie odczytać i podać jego wartość jako nagłówek dołączony do żądań AJAX. Na przykład, Angular zawiera wbudowaną ochronę XSRF, która domyślnie odczytuje cookie o nazwie XSRF-TOKEN.

Wymagaj weryfikacji antyfałszerstwowej

Filtr akcji ValidateAntiForgeryToken można zastosować do pojedynczej akcji, kontrolera lub globalnie. Żądania wysyłane do akcji, które mają zastosowany ten filtr, są blokowane, chyba że żądanie zawiera prawidłowy token antyforgery:

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

    return RedirectToAction();
}

Atrybut ValidateAntiForgeryToken wymaga tokenu dla żądań do metod akcji, które wskazuje, łącznie z żądaniami HTTP GET. ValidateAntiForgeryToken Jeśli atrybut jest stosowany na kontrolerach aplikacji, można go zastąpić atrybutem IgnoreAntiforgeryToken .

Automatyczne weryfikowanie tokenów antyforgeryjnych tylko pod kątem niebezpiecznych metod HTTP

Zamiast szeroko stosować ValidateAntiForgeryToken atrybut, a następnie zastąpić go atrybutami IgnoreAntiforgeryToken , można użyć atrybutu AutoValidateAntiforgeryToken . Ten atrybut działa identycznie z atrybutem ValidateAntiForgeryToken , z tą różnicą, że nie wymaga tokenów dla żądań wykonanych przy użyciu następujących metod HTTP:

  • GET
  • głowa
  • Opcje
  • TRACE

Zalecamy szerokie korzystanie z AutoValidateAntiforgeryToken w scenariuszach innych niż API. Ten atrybut zapewnia, że akcje POST są domyślnie chronione. Alternatywą jest ignorowanie tokenów antyforgeryjnych domyślnie, chyba że ValidateAntiForgeryToken jest stosowane do poszczególnych metod akcji. Jest bardziej prawdopodobne w tym scenariuszu, aby metoda akcji POST została pozostawiona bez ochrony przez pomyłkę, pozostawiając aplikację podatną na ataki CSRF. Wszystkie poSTs powinny wysłać token antyforgery.

Interfejsy API nie mają mechanizmu automatycznego wysyłania części tokenu, która nie jest częścią cookie. Implementacja prawdopodobnie zależy od implementacji kodu klienta. Poniżej przedstawiono kilka przykładów:

Przykład na poziomie klasy:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Przykład globalny:

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

Zastępowanie globalnych lub kontrolerowych atrybutów antyforgery

Filtr IgnoreAntiforgeryToken służy do eliminowania potrzeby tokenu antyforgery dla danej akcji (lub kontrolera). Po zastosowaniu ten filtr zastępuje ValidateAntiForgeryToken i AutoValidateAntiforgeryToken filtry określone na wyższym poziomie (globalnie lub na kontrolerze).

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

    return RedirectToAction();
}

Odświeżanie tokenów po uwierzytelnieniu

Tokeny powinny być odświeżane po uwierzytelnieniu użytkownika przez przekierowanie użytkownika do strony widoku lub Razor stron.

JavaScript, AJAX i SPAs

W tradycyjnych aplikacjach opartych na kodzie HTML tokeny antyforgeryjne są przekazywane do serwera przy użyciu ukrytych pól formularza. W nowoczesnych aplikacjach opartych na języku JavaScript i usługach SPA wiele żądań jest wysyłanych programowo. Te żądania AJAX mogą używać innych technik, takich jak nagłówki żądań lub pliki cookie, w celu wysłania tokenu.

Jeśli pliki cookie są używane do przechowywania tokenów uwierzytelniania i uwierzytelniania żądań interfejsu API na serwerze, csrF jest potencjalnym problemem. Jeśli magazyn lokalny jest używany do przechowywania tokenu, luka w zabezpieczeniach CSRF może zostać usunięta, ponieważ wartości z magazynu lokalnego nie są wysyłane automatycznie do serwera z każdym żądaniem. Używanie pamięci lokalnej do przechowywania tokenu antyforgery na kliencie i wysyłania tokenu jako nagłówka żądania jest zalecane.

Blazor

Aby uzyskać więcej informacji, zobacz uwierzytelnianie i autoryzację w ASP.NET CoreBlazor.

JavaScript

Przy użyciu języka JavaScript z widokami token można utworzyć przy użyciu usługi z poziomu widoku. Wstrzyknąć usługę IAntiforgery do widoku i wywołać 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>
}

W poprzednim przykładzie użyto języka JavaScript do odczytania ukrytej wartości pola nagłówka AJAX POST.

Takie podejście eliminuje konieczność bezpośredniego czynienia z ustawianiem plików cookie z serwera lub odczytywaniem ich z klienta. Jeśli iniekcja usługi IAntiforgery nie jest możliwa, użyj języka JavaScript, aby uzyskać dostęp do tokenów w ciasteczkach.

  • Tokeny dostępu w dodatkowym żądaniu do serwera, zazwyczaj same-origin.
  • Użyj zawartości elementu cookie, aby utworzyć nagłówek z wartością tokenu.

Zakładając, że skrypt wysyła token w nagłówku żądania o nazwie X-XSRF-TOKEN, skonfiguruj usługę antyforgery, aby wyszukać nagłówek X-XSRF-TOKEN.

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

W poniższym przykładzie dodano chroniony punkt końcowy, który zapisuje token żądania do czytelnego cookiekodu JavaScript:

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

W poniższym przykładzie użyto języka JavaScript do utworzenia żądania AJAX w celu uzyskania tokenu i wykonania innego żądania z odpowiednim nagłówkiem:

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

Uwaga

Gdy token antyforgery jest udostępniany zarówno w nagłówku żądania, jak i w ładunku formularza, tylko token w nagłówku jest weryfikowany.

Antyforgery z minimalnymi interfejsami API

Wywołaj AddAntiforgery i UseAntiforgery(IApplicationBuilder) zarejestruj usługi antyfałszerstwa w DI. Tokeny chroniące przed fałszerzami służą do eliminowania ataków fałszerzowania żądań między witrynami.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

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

app.Run();

Oprogramowanie pośredniczące chroniące przed fałszerzami:

Token antyforgery jest weryfikowany tylko wtedy, gdy:

  • Punkt końcowy zawiera metadane implementujące IAntiforgeryMetadata, przy czym RequiresValidation=true.
  • Metoda HTTP skojarzona z punktem końcowym jest odpowiednią metodą HTTP. Odpowiednie metody to wszystkie metody HTTP z wyjątkiem metod TRACE, OPTIONS, HEAD i GET.
  • Żądanie jest skojarzone z prawidłowym punktem końcowym.

Uwaga: Po ręcznym włączeniu, oprogramowanie pośredniczące antyfałszywe musi działać po oprogramowaniu pośredniczącym odpowiedzialnym za uwierzytelnianie i autoryzację, aby zapobiec odczytywaniu danych formularza, gdy użytkownik nie jest uwierzytelniony.

Domyślnie minimalne interfejsy API, które akceptują dane formularza, wymagają walidacji tokenu antywłamaniowego.

Rozważmy następującą 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>
";
}

Powyższy kod ma trzy argumenty: akcję, token antyforgery, oraz bool, który wskazuje, czy token powinien być używany.

Rozważmy następujący przykład:

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

W poprzednim kodzie przesyła do:

  • /todo wymaga prawidłowego tokenu antyforgery.
  • /todo2 nie wymagają prawidłowego tokenu antyforgery, ponieważ DisableAntiforgery jest wywoływany.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

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

A POST na:

  • /todo z formularza wygenerowanego przez punkt końcowy / kończy się powodzeniem, ponieważ token antyfałszerstwa jest prawidłowy.
  • /todo z powodu braku komponentu zabezpieczającego przeciwdziałającego fałszerstwom w formularzu wygenerowanym przez /SkipToken kończy się niepowodzeniem.
  • /todo2 z formularza wygenerowanego przez /DisableAntiforgery punkt końcowy kończy się sukcesem, ponieważ antyfałszywka nie jest wymagana.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

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

Po przesłaniu formularza bez prawidłowego tokenu antyforgery:

  • W środowisku deweloperskim zgłaszany jest wyjątek.
  • W środowisku produkcyjnym jest rejestrowany komunikat.

Uwierzytelnianie systemu Windows i pliki cookie ochrony przed fałszerzami

W przypadku korzystania z uwierzytelniania systemu Windows punkty końcowe aplikacji muszą być chronione przed atakami CSRF w taki sam sposób, jak w przypadku plików cookie. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera i punktów końcowych, które muszą być chronione przed atakami CSRF.

Rozszerzanie funkcji antyfałszerstwa

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie funkcjonalności systemu chroniącego przed CSRF poprzez przesyłanie dodatkowych danych w każdym tokenie. Metoda GetAdditionalData jest wywoływana za każdym razem, gdy generowany jest token pola, a wartość zwracana jest osadzona w tym wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, liczbę losową lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData w celu weryfikacji tych danych podczas weryfikacji tokenu. Nazwa użytkownika klienta jest już osadzona w wygenerowanych tokenach, więc nie ma potrzeby dołączania tych informacji. Jeśli token zawiera dane uzupełniające, ale IAntiForgeryAdditionalDataProvider nie jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby

Fałszowanie żądań między witrynami (znane również jako XSRF lub CSRF) to atak na aplikacje webowe, w którym złośliwa aplikacja internetowa może wpływać na interakcję między przeglądarką klienta a aplikacją, która jej ufa. Te ataki są możliwe, ponieważ przeglądarki internetowe automatycznie wysyłają niektóre typy tokenów uwierzytelniania z każdym żądaniem do witryny internetowej. Ta forma wykorzystania jest również znana jako atak jednym kliknięciem lub przechwycenie sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika.

Przykład ataku CSRF:

  1. Użytkownik loguje się do www.good-banking-site.example.com przy użyciu uwierzytelniania formularzy. Serwer uwierzytelnia użytkownika i wystawia odpowiedź zawierającą uwierzytelnianie cookie. Witryna jest podatna na ataki, ponieważ ufa wszelkim żądaniom otrzymanym przy użyciu prawidłowego uwierzytelniania cookie.

  2. Użytkownik odwiedza złośliwą witrynę. www.bad-crook-site.example.com

    Złośliwa witryna www.bad-crook-site.example.com, zawiera formularz HTML podobny do następującego przykładu:

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

    Zwróć uwagę, że formularz action wysyła dane do witryny podatnej na zagrożenia, a nie do złośliwej. Jest to część "cross-site" w kontekście CSRF.

  3. Użytkownik wybierze przycisk Prześlij. Przeglądarka wysyła żądanie i automatycznie dołącza uwierzytelnianie cookie dla żądanej domeny. www.good-banking-site.example.com

  4. Żądanie jest uruchamiane na www.good-banking-site.example.com serwerze z kontekstem uwierzytelniania użytkownika i może wykonać dowolną akcję, którą może wykonać uwierzytelniony użytkownik.

Oprócz scenariusza, w którym użytkownik wybiera przycisk do przesłania formularza, złośliwa witryna może:

  • Uruchom skrypt, który automatycznie przesyła formularz.
  • Wyślij formularz jako żądanie AJAX.
  • Ukryj formularz przy użyciu arkusza CSS.

Te alternatywne scenariusze nie wymagają żadnej akcji ani danych wejściowych od użytkownika innego niż początkowo odwiedzanie złośliwej witryny.

Korzystanie z protokołu HTTPS nie zapobiega atakowi CSRF. Złośliwa witryna może równie łatwo wysłać żądanie https://www.good-banking-site.example.com/, jak i niezabezpieczone żądanie.

Niektóre ataki są celem punktów końcowych, które odpowiadają na żądania GET, w takim przypadku tag obrazu może służyć do wykonania akcji. Ta forma ataku jest powszechna w witrynach forum, które zezwalają na obrazy, ale blokują język JavaScript. Aplikacje, które zmieniają stan żądań GET, w których zmieniane są zmienne lub zasoby, są narażone na złośliwe ataki. Żądania GET, które zmieniają stan, są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

Ataki CSRF są możliwe dla aplikacji internetowych, które używają plików cookie do uwierzytelniania, ponieważ:

  • Przeglądarki przechowują pliki cookie wystawione przez aplikację internetową.
  • Przechowywane pliki cookie obejmują pliki cookie sesji dla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie pliki cookie skojarzone z domeną do aplikacji internetowej, niezależnie od tego, jak żądanie do aplikacji zostało wygenerowane w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystywania plików cookie. Na przykład uwierzytelnianie podstawowe i z wykorzystaniem metody Digest jest również podatne. Po zalogowaniu się użytkownika przy użyciu uwierzytelniania podstawowego lub szyfrowego przeglądarka automatycznie wysyła poświadczenia do momentu zakończenia sesji.

W tym kontekście sesja odnosi się do sesji po stronie klienta, podczas której użytkownik jest uwierzytelniany. Nie ma to związku z sesjami po stronie serwera lub ASP.NET Core Session Middleware.

Użytkownicy mogą chronić się przed lukami w zabezpieczeniach CSRF, stosując środki ostrożności:

  • Wyloguj się z aplikacji internetowych po zakończeniu korzystania z nich.
  • Okresowo usuwaj pliki cookie przeglądarki.

Jednak luki w zabezpieczeniach CSRF są zasadniczo problemem z aplikacją internetową, a nie użytkownikiem końcowym.

Podstawy uwierzytelniania

Cookie-bazowane uwierzytelnianie jest popularną formą uwierzytelniania. Systemy uwierzytelniania oparte na tokenach rosną na popularności, szczególnie w przypadku aplikacji jednostronicowych (SPA).

Gdy użytkownik uwierzytelnia się przy użyciu swojej nazwy użytkownika i hasła, zostaje mu wydany token zawierający uprawnienia do uwierzytelniania i autoryzacji. Token jest przechowywany jako cookie element, który jest wysyłany z każdym żądaniem wysyłanym przez klienta. Generowanie i weryfikowanie cookie jest wykonywane przez middleware uwierzytelniający. Oprogramowanie pośredniczące serializuje tożsamość użytkownika do zaszyfrowanego cookie. W kolejnych żądaniach middleware weryfikuje element cookie, odtwarza tożsamość i przypisuje ją do właściwości HttpContext.User.

Uwierzytelnianie oparte na tokenach

Po uwierzytelnieniu użytkownika otrzymuje token (a nie token antyforgery). Token zawiera informacje o użytkowniku w postaci oświadczeń lub tokenu referencyjnego wskazującego aplikację na stan użytkownika utrzymywany w aplikacji. Gdy użytkownik próbuje uzyskać dostęp do zasobu wymagającego uwierzytelnienia, token jest wysyłany do aplikacji z dodatkowym nagłówkiem autoryzacji w postaci tokenu Bearer. Takie podejście sprawia, że aplikacja jest bezstanowa. W każdym kolejnym żądaniu token jest przekazywany w żądaniu weryfikacji po stronie serwera. Ten token nie jest zaszyfrowany; jest zakodowany. Na serwerze token jest dekodowany w celu uzyskania dostępu do informacji. Aby wysłać token do kolejnych żądań, zapisz token w magazynie lokalnym przeglądarki. Zapisanie tokenu w lokalnej pamięci przeglądarki, a następnie jego pobranie i użycie jako tokenu typu bearer zapewnia ochronę przed atakami CSRF. Jednak jeśli aplikacja jest podatna na wstrzyknięcie skryptu za pośrednictwem XSS lub naruszonego zewnętrznego pliku javascript, cyberattacker może pobrać dowolną wartość z magazynu lokalnego i wysłać ją do siebie. ASP.NET Core koduje domyślnie wszystkie dane wyjściowe po stronie serwera ze zmiennych, co zmniejsza ryzyko wystąpienia XSS. Jeśli to zachowanie zostanie zastąpione przy użyciu kodu Html.Raw lub niestandardowego z niezaufanymi danymi wejściowymi, może to spowodować zwiększenie ryzyka użycia usługi XSS.

Nie obawiaj się luki w zabezpieczeniach CSRF, jeśli token jest przechowywany w magazynie lokalnym przeglądarki. CSRF jest problemem, gdy token jest przechowywany w cookie. Aby uzyskać więcej informacji, zobacz problem na GitHubie Przykład kodu SPA dodaje dwa pliki cookie.

Wiele aplikacji hostowanych w jednej domenie

Współdzielone środowiska hostingowe są narażone na porwanie sesji, logowanie CSRF i inne ataki.

Chociaż example1.contoso.net i example2.contoso.net są różnymi hostami, istnieje niejawna relacja zaufania między hostami w domenie *.contoso.net . Ta niejawna relacja zaufania umożliwia hostom, którym potencjalnie nie można ufać, wpływ na pliki cookie innych (zasady tego samego pochodzenia, które zarządzają żądaniami AJAX, niekoniecznie mają zastosowanie do plików cookie HTTP).

Ataki wykorzystujące zaufane pliki cookie między aplikacjami hostowanymi w tej samej domenie mogą być zapobiegane poprzez niedzielenie domen. Gdy każda aplikacja jest hostowana we własnej domenie, nie ma niejawnej cookie relacji zaufania do wykorzystania.

Ochrona przed fałszerstwem w ASP.NET Core

Ostrzeżenie

ASP.NET Core implementuje ochronę przed fałszerzją przy użyciu ASP.NET Core Data Protection. Stos ochrony danych musi być skonfigurowany do pracy w farmie serwerów. Aby uzyskać więcej informacji, zobacz Konfigurowanie ochrony danych.

Oprogramowanie pośredniczące chroniące przed fałszerzami jest dodawane do kontenera wstrzykiwania zależności, gdy jeden z następujących interfejsów API jest wywoływany w pliku Program.cs:

Element FormTagHelper wprowadza tokeny chroniące przed fałszerstwem do elementów formularza HTML. Następujące znaczniki w Razor pliku automatycznie generują tokeny chroniące przed fałszerzami:

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

Podobnie, IHtmlHelper.BeginForm generuje domyślnie tokeny antyforgery, jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyfałszyfikacyjnych dla elementów formularza HTML odbywa się, gdy znacznik <form> zawiera atrybut method="post" i spełniony jest jeden z następujących warunków:

  • Atrybut akcji jest pusty (action="").
  • Atrybut akcji nie jest podany (<form method="post">).

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML można wyłączyć:

  • Jawnie wyłącz tokeny ochrony przed fałszerzami za pomocą atrybutu asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Element formularza jest wyłączony z Tag Helpers przy użyciu symbolu ! wyłączenia:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Usuń element FormTagHelper z widoku. Element FormTagHelper można usunąć z widoku, dodając następującą dyrektywę Razor do widoku:

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

Uwaga

Razor Strony są automatycznie chronione przed plikami XSRF/CSRF. Aby uzyskać więcej informacji, zobacz XSRF/CSRF i Razor Pages.

Najczęstszym podejściem do obrony przed atakami CSRF jest użycie wzorca tokenu synchronizatora (STP). Usługa STP jest używana, gdy użytkownik żąda strony z danymi formularza:

  1. Serwer wysyła token skojarzony z tożsamością bieżącego użytkownika do klienta.
  2. Klient wysyła token z powrotem do serwera w celu weryfikacji.
  3. Jeśli serwer otrzyma token, który nie jest zgodny z tożsamością uwierzytelnionego użytkownika, żądanie zostanie odrzucone.

Token jest unikatowy i nieprzewidywalny. Token może również służyć do zapewnienia prawidłowego sekwencjonowania serii żądań (na przykład zapewnienia sekwencji żądań strony 1 > strona 2 > strona 3). Wszystkie formularze w szablonach ASP.NET Core MVC i Razor Pages generują tokeny antyforgery. Poniższa para przykładów widoków generuje tokeny chroniące przed fałszerzami:

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

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

Jawnie dodaj token antyfałszerstwa do elementu <form> bez użycia Tag Helpers, używając pomocnika HTML @Html.AntiForgeryToken.

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

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

W każdym z powyższych przypadków ASP.NET Core dodaje ukryte pole formularza podobne do następującego przykładu:

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

ASP.NET Core zawiera trzy filtry do pracy z tokenami antyforgeryjnymi:

Ochrona przed fałszerstwem z AddControllers

Wywołanie AddControllersnie włącza tokeny antyforgeryjne. AddControllersWithViews musi być wywołany w celu uzyskania wbudowanej obsługi tokenów antyforgery.

Wiele kart przeglądarki i wzorzec tokenu synchronizatora

W przypadku wzorca tokenu synchronizatora tylko ostatnio załadowana strona zawiera prawidłowy token antyforgery. Korzystanie z wielu kart może być problematyczne. Jeśli na przykład użytkownik otworzy wiele kart:

  • Tylko najnowsza załadowana karta zawiera prawidłowy token antyforgery.
  • Żądania wysyłane z wcześniej załadowanych kart kończą się błędem: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Rozważ alternatywne wzorce ochrony CSRF, jeśli stanowi to problem.

Konfigurowanie ochrony przed fałszerzją za pomocą polecenia AntiforgeryOptions

Dostosowywanie AntiforgeryOptions w programie Program.cs:

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

Ustaw właściwości ochrony przed fałszerzami Cookie przy użyciu właściwości CookieBuilder klasy, jak pokazano w poniższej tabeli.

Opcja Opis
Cookie Określa ustawienia używane do tworzenia plików cookie chroniących przed fałszerzami.
FormFieldName Nazwa pola ukrytego formularza używanego przez system antyforgery do renderowania tokenów antyforgeryjnych w widokach.
HeaderName Nazwa nagłówka używanego przez system antyforgery. Jeśli nullsystem uwzględnia tylko dane formularza.
SuppressXFrameOptionsHeader Określa, czy pomijać generowanie nagłówka X-Frame-Options . Domyślnie nagłówek jest generowany z wartością "SAMEORIGIN". Wartość domyślna to false.

Aby uzyskać więcej informacji, zobacz CookieAuthenticationOptions.

Generowanie tokenów antyforgeryjnych za pomocą polecenia IAntiforgery

IAntiforgery udostępnia interfejs API do konfigurowania funkcji ochrony przed fałszerstwami. IAntiforgery można zażądać w Program.cs za pomocą WebApplication.Services. W poniższym przykładzie użyto oprogramowania pośredniczącego ze strony głównej aplikacji do wygenerowania tokenu antyforgery i wysłania go w odpowiedzi jako cookie:

app.UseRouting();

app.UseAuthorization();

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

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

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

    return next(context);
});

Wcześniejszy przykład ustawia cookie nazwany XSRF-TOKEN. Klient może to cookie odczytać i podać jego wartość jako nagłówek dołączony do żądań AJAX. Na przykład Angular zawiera wbudowaną ochronę XSRF, która domyślnie odczytuje cookie o nazwie XSRF-TOKEN.

Wymaganie weryfikacji ochrony przed fałszerzami

Filtr akcji ValidateAntiForgeryToken można zastosować do pojedynczej akcji, kontrolera lub globalnie. Żądania wysyłane do akcji, które mają zastosowany ten filtr, są blokowane, chyba że żądanie zawiera prawidłowy token antyforgery:

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

    return RedirectToAction();
}

Atrybut ValidateAntiForgeryToken wymaga tokenu dla żądań do metod akcji, do których się odnosi, w tym żądań HTTP GET. ValidateAntiForgeryToken Jeśli atrybut jest stosowany na kontrolerach aplikacji, można go zastąpić atrybutem IgnoreAntiforgeryToken .

Automatyczne weryfikowanie tokenów antyforgeryjnych tylko pod kątem niebezpiecznych metod HTTP

Zamiast szeroko stosować ValidateAntiForgeryToken atrybut, a następnie zastąpić go atrybutami IgnoreAntiforgeryToken , można użyć atrybutu AutoValidateAntiforgeryToken . Ten atrybut działa identycznie z atrybutem ValidateAntiForgeryToken , z tą różnicą, że nie wymaga tokenów dla żądań wykonanych przy użyciu następujących metod HTTP:

  • GET
  • NAGŁÓWEK
  • OPCJE
  • ślad

Zalecamy szerokie stosowanie AutoValidateAntiforgeryToken w scenariuszach innych niż API. Ten atrybut zapewnia, że akcje POST są domyślnie chronione. Alternatywą jest ignorowanie tokenów antyforgeryjnych domyślnie, chyba że ValidateAntiForgeryToken jest stosowane do poszczególnych metod akcji. Jest bardziej prawdopodobne w tym scenariuszu, aby metoda akcji POST została pozostawiona bez ochrony przez pomyłkę, pozostawiając aplikację podatną na ataki CSRF. Wszystkie POSTy powinny wysłać token antyfałszerstwa.

Interfejsy API nie mają automatycznego mechanizmu do wysyłania części tokenu, która nie jest częścią cookie. Implementacja prawdopodobnie zależy od implementacji kodu klienta. Poniżej przedstawiono kilka przykładów:

Przykład na poziomie klasy:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Przykład globalny:

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

Zastępowanie atrybutów globalnych lub atrybutów antyforgery kontrolera

Filtr IgnoreAntiforgeryToken służy do eliminowania potrzeby tokenu antyforgery dla danej akcji (lub kontrolera). Po zastosowaniu ten filtr zastępuje ValidateAntiForgeryToken i AutoValidateAntiforgeryToken filtry określone na wyższym poziomie (globalnie lub na kontrolerze).

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

    return RedirectToAction();
}

Odświeżanie tokenów po uwierzytelnieniu

Tokeny powinny być odświeżane po uwierzytelnieniu użytkownika przez przekierowanie użytkownika do widoku lub strony 'Pages'.

JavaScript, AJAX i SPAs

W tradycyjnych aplikacjach opartych na kodzie HTML tokeny antyforgeryjne są przekazywane do serwera przy użyciu ukrytych pól formularza. W nowoczesnych aplikacjach opartych na języku JavaScript i usługach SPA wiele żądań jest wysyłanych programowo. Te żądania AJAX mogą używać innych technik (takich jak nagłówki żądań lub pliki cookie) w celu wysłania tokenu.

Jeśli pliki cookie są używane do przechowywania tokenów uwierzytelniania i uwierzytelniania żądań interfejsu API na serwerze, csrF jest potencjalnym problemem. Jeśli magazyn lokalny jest używany do przechowywania tokenu, luka w zabezpieczeniach CSRF może zostać usunięta, ponieważ wartości z magazynu lokalnego nie są wysyłane automatycznie do serwera z każdym żądaniem. Używanie pamięci lokalnej do przechowywania tokenu antyforgery na kliencie i wysyłanie tokenu jako nagłówka żądania jest zalecanym podejściem.

JavaScript

Przy użyciu języka JavaScript z widokami token można utworzyć przy użyciu usługi z poziomu widoku. Wstrzyknij usługę IAntiforgery do widoku i wywołaj 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>
}

W poprzednim przykładzie użyto języka JavaScript do odczytania ukrytej wartości pola nagłówka AJAX POST.

Takie podejście eliminuje konieczność bezpośredniego czynienia z ustawianiem plików cookie z serwera lub odczytywaniem ich z klienta. Kiedy jednak iniekcja usługi IAntiforgery nie jest możliwa, użyj JavaScript, aby uzyskać dostęp do tokenów w cookies.

  • Tokeny dostępu w dodatkowym żądaniu do serwera, zazwyczaj same-origin.
  • Użyj zawartości elementu cookie, aby utworzyć nagłówek z wartością tokenu.

Zakładając, że skrypt wysyła token w nagłówku żądania o nazwie X-XSRF-TOKEN, skonfiguruj usługę antyforgery, aby wyszukała nagłówek X-XSRF-TOKEN.

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

W poniższym przykładzie dodano chroniony punkt końcowy, który zapisuje token żądania do czytelnego cookiekodu JavaScript:

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

W poniższym przykładzie użyto języka JavaScript do utworzenia żądania AJAX w celu uzyskania tokenu i wykonania innego żądania z odpowiednim nagłówkiem:

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

Uwaga

Gdy token antyforgery jest udostępniany zarówno w nagłówku żądania, jak i w treści formularza, tylko token w nagłówku jest weryfikowany.

Zabezpieczenie przed fałszerstwem z użyciem minimalnych API

Minimal APIs Nie obsługują użycia uwzględnionych filtrów (ValidateAntiForgeryToken, AutoValidateAntiforgeryToken, IgnoreAntiforgeryToken), jednak IAntiforgery udostępnia wymagane interfejsy API do zweryfikowania żądania.

Poniższy przykład tworzy filtr, który weryfikuje token antyforgery:

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

        });
    }
}

Następnie można zastosować filtr do punktu końcowego:

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

Uwierzytelnianie systemu Windows i pliki cookie ochrony przed fałszerzami

W przypadku korzystania z uwierzytelniania systemu Windows punkty końcowe aplikacji muszą być chronione przed atakami CSRF w taki sam sposób, jak w przypadku plików cookie. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera i punktów końcowych, które muszą być chronione przed atakami CSRF.

Rozszerzenie mechanizmów antyfałszerstwa

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie działania systemu anty-CSRF poprzez przekazywanie dodatkowych danych wewnątrz każdego tokena. Metoda GetAdditionalData jest wywoływana za każdym razem, gdy generowany jest token pola, a wartość zwracana jest zawarta w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, nonce lub inną dowolną wartość, a następnie wywołać metodę ValidateAdditionalData w celu weryfikacji tych danych, gdy token zostanie zweryfikowany. Nazwa użytkownika klienta jest już osadzona w wygenerowanych tokenach, więc nie ma potrzeby dołączania tych informacji. Jeśli token zawiera dane uzupełniające, ale IAntiForgeryAdditionalDataProvider nie jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby

Fałszerstwo żądań między witrynami (znane również jako XSRF lub CSRF) to atak na aplikacje hostowane w sieci, w którym złośliwa aplikacja internetowa może wpływać na interakcję między przeglądarką klienta a aplikacją internetową, która ufa tej przeglądarce. Te ataki są możliwe, ponieważ przeglądarki internetowe automatycznie wysyłają niektóre typy tokenów uwierzytelniania z każdym żądaniem do witryny internetowej. Ta forma wykorzystania jest również znana jako atak jednym kliknięciem lub przejęcie sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika.

Przykład ataku CSRF:

  1. Użytkownik loguje się do www.good-banking-site.example.com za pomocą uwierzytelniania formularzy. Serwer uwierzytelnia użytkownika i wystawia odpowiedź zawierającą uwierzytelnianie cookie. Witryna jest podatna na ataki, ponieważ ufa wszelkim żądaniom otrzymanym przy użyciu prawidłowego uwierzytelniania cookie.

  2. Użytkownik odwiedza złośliwą witrynę. www.bad-crook-site.example.com

    Złośliwa witryna www.bad-crook-site.example.com, zawiera formularz HTML podobny do następującego przykładu:

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

    Zwróć uwagę, że formularz action przesyła wpisy do witryny podatnej na zagrożenia, a nie do złośliwej witryny. Jest to część CSRF "międzystronicowa".

  3. Użytkownik wybierze przycisk Prześlij. Przeglądarka wysyła żądanie i automatycznie dołącza uwierzytelnianie cookie dla żądanej domeny. www.good-banking-site.example.com

  4. Żądanie jest uruchamiane na www.good-banking-site.example.com serwerze z kontekstem uwierzytelniania użytkownika i może wykonać dowolną akcję, którą może wykonać uwierzytelniony użytkownik.

Oprócz scenariusza, w którym użytkownik wybiera przycisk do przesłania formularza, złośliwa witryna może:

  • Uruchom skrypt, który automatycznie przesyła formularz.
  • Wyślij formularz jako żądanie AJAX.
  • Ukryj formularz przy użyciu arkusza CSS.

Te alternatywne scenariusze nie wymagają żadnej akcji ani danych wejściowych od użytkownika innego niż początkowo odwiedzanie złośliwej witryny.

Korzystanie z protokołu HTTPS nie zapobiega atakowi CSRF. Złośliwa witryna może równie łatwo wysłać żądanie https://www.good-banking-site.example.com/, jak i niezabezpieczone żądanie.

Niektóre ataki są celem punktów końcowych, które odpowiadają na żądania GET, w takim przypadku tag obrazu może służyć do wykonania akcji. Ta forma ataku jest powszechna w witrynach forum, które zezwalają na obrazy, ale blokują język JavaScript. Aplikacje, które zmieniają stan żądań GET, w których zmieniane są zmienne lub zasoby, są narażone na złośliwe ataki. Żądania GET, które zmieniają stan, są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

Ataki CSRF są możliwe dla aplikacji internetowych, które używają plików cookie do uwierzytelniania, ponieważ:

  • Przeglądarki przechowują pliki cookie wystawione przez aplikację internetową.
  • Przechowywane pliki cookie obejmują pliki cookie sesji dla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie pliki cookie skojarzone z domeną do aplikacji internetowej, niezależnie od tego, jak żądanie do aplikacji zostało wygenerowane w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystywania plików cookie. Na przykład, uwierzytelnianie podstawowe i uwierzytelnianie typu Digest są również podatne. Po zalogowaniu się użytkownika przy użyciu uwierzytelniania podstawowego lub szyfrowego przeglądarka automatycznie wysyła poświadczenia do momentu zakończenia sesji.

W tym kontekście sesja odnosi się do sesji po stronie klienta, podczas której użytkownik jest uwierzytelniany. Nie ma to związku z sesjami po stronie serwera lub oprogramowaniem pośredniczącym sesji podstawowej ASP.NET.

Użytkownicy mogą chronić się przed lukami w zabezpieczeniach CSRF, stosując środki ostrożności:

  • Wyloguj się z aplikacji internetowych po zakończeniu korzystania z nich.
  • Okresowo usuwaj pliki cookie przeglądarki.

Jednak luki w zabezpieczeniach CSRF są zasadniczo problemem z aplikacją internetową, a nie użytkownikiem końcowym.

Podstawy uwierzytelniania

CookieUwierzytelnianie oparte na protokole jest popularną formą uwierzytelniania. Systemy uwierzytelniania oparte na tokenach rosną na popularności, szczególnie w przypadku aplikacji jednostronicowych (SPA).

Gdy użytkownik uwierzytelnia się za pomocą nazwy użytkownika i hasła, otrzymuje token zawierający bilet uwierzytelniania, który można użyć do uwierzytelniania i autoryzacji. Token jest przechowywany jako cookie element, który jest wysyłany z każdym żądaniem wysyłanym przez klienta. Generowanie i weryfikowanie cookie jest wykonywane przez warstwę pośrednią uwierzytelniania Cookie. Oprogramowanie pośredniczące serializuje głównego użytkownika do zaszyfrowanego cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje element cookie, ponownie tworzy podmiot i przypisuje podmiot do właściwości HttpContext.User.

Uwierzytelnianie oparte na tokenach

Po uwierzytelnieniu użytkownika otrzymuje token (a nie token antyforgery). Token zawiera informacje o użytkowniku w postaci oświadczeń lub tokenu referencyjnego wskazującego aplikację na stan użytkownika utrzymywany w aplikacji. Gdy użytkownik próbuje uzyskać dostęp do zasobu wymagającego uwierzytelnienia, token jest wysyłany do aplikacji z dodatkowym nagłówkiem autoryzacyjnym w postaci Bearer token. Takie podejście sprawia, że aplikacja jest bezstanowa. W każdym kolejnym żądaniu token jest przekazywany w żądaniu weryfikacji po stronie serwera. Ten token nie jest zaszyfrowany; jest zakodowany. Na serwerze token jest dekodowany w celu uzyskania dostępu do informacji. Aby wysłać token do kolejnych żądań, zapisz token w magazynie lokalnym przeglądarki. Nie obawiaj się luki w zabezpieczeniach CSRF, jeśli token jest przechowywany w magazynie lokalnym przeglądarki. CSRF jest problemem, gdy token jest przechowywany w obiekcie cookie. Aby uzyskać więcej informacji, zobacz problem GitHub Przykład kodu SPA dodaje dwa pliki cookie.

Wiele aplikacji hostowanych w jednej domenie

Współdzielone środowiska hostingu są podatne na porwanie sesji, CSRF logowania i inne ataki.

Chociaż example1.contoso.net i example2.contoso.net są różnymi hostami, istnieje niejawna relacja zaufania między hostami w domenie *.contoso.net . Ta niejawna relacja zaufania umożliwia potencjalnie niezaufanym hostom wpływanie na pliki cookie innych hostów (zasady samego pochodzenia, które zarządzają żądaniami AJAX, nie zawsze odnoszą się do plików cookie HTTP).

Ataki wykorzystujące pliki cookie o ograniczonym zaufaniu między aplikacjami hostowanymi w tej samej domenie mogą być zapobiegane przez niedzielenie się domenami. Gdy każda aplikacja jest hostowana we własnej domenie, nie ma niejawnej cookie relacji zaufania do wykorzystania.

Zabezpieczenie przed fałszerstwem (Antiforgery) w ASP.NET Core

Ostrzeżenie

ASP.NET Core implementuje ochronę przed fałszerzją przy użyciu ASP.NET Core Data Protection. Stos ochrony danych musi być skonfigurowany do pracy w farmie serwerów. Aby uzyskać więcej informacji, zobacz Konfigurowanie ochrony danych.

Oprogramowanie pośredniczące chroniące przed fałszerzami jest dodawane do kontenera wstrzykiwania zależności, gdy jeden z następujących interfejsów API jest wywoływany w pliku Program.cs:

Element FormTagHelper wprowadza tokeny chroniące przed fałszerstwem do elementów formularza HTML. Następujące znaczniki w Razor pliku automatycznie generują tokeny chroniące przed fałszerzami:

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

Podobnie, IHtmlHelper.BeginForm domyślnie generuje tokeny antyforgery, jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML odbywa się, gdy tag <form> zawiera atrybut method="post" i spełniony jest jeden z następujących warunków:

  • Atrybut akcji jest pusty (action="").
  • Atrybut akcji nie jest podany (<form method="post">).

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML można wyłączyć:

  • Jawnie wyłącz tokeny ochrony przed fałszerzami za pomocą atrybutu asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • Element formularza jest wyłączony z pomocników tagów przy użyciu symbolu rezygnacji: !

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Usuń element FormTagHelper z widoku. Element FormTagHelper można usunąć z widoku, dodając następującą dyrektywę Razor do widoku:

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

Uwaga

Razor Strony są automatycznie chronione przed plikami XSRF/CSRF. Aby uzyskać więcej informacji, zobacz XSRF/CSRF i Razor Pages.

Najczęstszym podejściem do obrony przed atakami CSRF jest użycie wzorca tokenu synchronizatora (STP). Usługa STP jest używana, gdy użytkownik żąda strony z danymi formularza:

  1. Serwer wysyła token skojarzony z tożsamością bieżącego użytkownika do klienta.
  2. Klient wysyła token z powrotem do serwera w celu weryfikacji.
  3. Jeśli serwer otrzyma token, który nie jest zgodny z tożsamością uwierzytelnionego użytkownika, żądanie zostanie odrzucone.

Token jest unikatowy i nieprzewidywalny. Token może również służyć do zapewnienia prawidłowego sekwencjonowania serii żądań (na przykład zapewnienia sekwencji żądań strony 1 > strona 2 > strona 3). Wszystkie formularze w szablonach ASP.NET Core MVC i Razor Pages generują tokeny antyforgery. Poniższa para przykładów widoków generuje tokeny chroniące przed fałszerzami:

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

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

Jawnie dodaj token antyforgery do elementu <form> bez użycia pomocników tagów, korzystając z pomocnika HTML @Html.AntiForgeryToken.

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

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

W każdym z powyższych przypadków ASP.NET Core dodaje ukryte pole formularza podobne do następującego przykładu:

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

ASP.NET Core zawiera trzy filtry do pracy z tokenami antyforgeryjnymi:

Antiforgery z AddControllers

Wywołanie AddControllers nie włącza tokenów antyforgeryjnych. AddControllersWithViews musi być wywoływany, aby mieć wbudowaną obsługę tokenów antyforgery.

Wiele kart przeglądarki i wzorzec tokenu synchronizatora

W przypadku wzorca tokenu synchronizatora tylko ostatnio załadowana strona zawiera prawidłowy token antyforgery. Korzystanie z wielu kart może być problematyczne. Na przykład, jeśli użytkownik otworzy wiele kart:

  • Tylko ostatnio załadowana karta zawiera prawidłowy token antyforgery.
  • Żądania wysyłane z poprzednio załadowanych kart kończą się niepowodzeniem z powodu błędu: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Rozważ alternatywne wzorce ochrony CSRF, jeśli stanowi to problem.

Konfigurowanie ochrony przed fałszerzją za pomocą polecenia AntiforgeryOptions

Dostosowywanie AntiforgeryOptions w programie Program.cs:

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

Ustaw właściwości ochrony przed fałszerzami Cookie przy użyciu właściwości CookieBuilder klasy, jak pokazano w poniższej tabeli.

Opcja Opis
Cookie Określa ustawienia używane do tworzenia plików cookie chroniących przed fałszerzami.
FormFieldName Nazwa ukrytego pola formularza używanego przez system antyfałszywania do renderowania tokenów antyfałszywania w widokach.
HeaderName Nazwa nagłówka używanego przez system antyfałszywkowy. Jeśli nullsystem uwzględnia tylko dane formularza.
SuppressXFrameOptionsHeader Określa, czy pomijać generowanie nagłówka X-Frame-Options . Domyślnie nagłówek jest generowany z wartością "SAMEORIGIN". Wartość domyślna to false.

Aby uzyskać więcej informacji, zobacz CookieAuthenticationOptions.

Generowanie tokenów antyforgeryjnych za pomocą polecenia IAntiforgery

IAntiforgery udostępnia interfejs API do konfigurowania funkcji ochrony przed fałszerstwami. IAntiforgery można zażądać w Program.cs przy użyciu polecenia WebApplication.Services. W poniższym przykładzie użyto oprogramowania pośredniczącego ze strony głównej aplikacji do wygenerowania tokenu antyforgery i wysłania go w odpowiedzi jako cookie:

app.UseRouting();

app.UseAuthorization();

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

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

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

    return next(context);
});

Poprzedni przykład nadaje cookie nazwę XSRF-TOKEN. Klient może to cookie odczytać i podać jego wartość jako nagłówek dołączony do żądań AJAX. Na przykład Angular zawiera wbudowaną ochronę XSRF, która domyślnie odczytuje element nazwany cookie.

Wymagaj walidacji antyfałszywkowej

Filtr akcji ValidateAntiForgeryToken można zastosować do pojedynczej akcji, kontrolera lub globalnie. Żądania wysyłane do akcji, które mają zastosowany ten filtr, są blokowane, chyba że żądanie zawiera prawidłowy token antyforgery:

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

    return RedirectToAction();
}

Atrybut ValidateAntiForgeryToken wymaga tokenu dla oznaczanych przez nie go metod akcji, w tym dla żądań HTTP GET. ValidateAntiForgeryToken Jeśli atrybut jest stosowany na kontrolerach aplikacji, można go zastąpić atrybutem IgnoreAntiforgeryToken .

Automatyczne weryfikowanie tokenów antyforgeryjnych tylko pod kątem niebezpiecznych metod HTTP

Zamiast szeroko stosować ValidateAntiForgeryToken atrybut, a następnie zastąpić go atrybutami IgnoreAntiforgeryToken , można użyć atrybutu AutoValidateAntiforgeryToken . Ten atrybut działa identycznie z atrybutem ValidateAntiForgeryToken , z tą różnicą, że nie wymaga tokenów dla żądań wykonanych przy użyciu następujących metod HTTP:

  • GET
  • NAGŁÓWEK
  • OPCJE
  • TRACE

Zalecamy, aby AutoValidateAntiforgeryToken był używany szeroko w sytuacjach innych niż interfejsy API. Ten atrybut zapewnia, że akcje POST są domyślnie chronione. Alternatywą jest ignorowanie tokenów antyforgeryjnych domyślnie, chyba że ValidateAntiForgeryToken jest stosowane do poszczególnych metod akcji. Jest bardziej prawdopodobne w tym scenariuszu, aby metoda akcji POST została pozostawiona bez ochrony przez pomyłkę, pozostawiając aplikację podatną na ataki CSRF. Wszystkie POST-y powinny wysłać token antyfałszerstwa.

Interfejsy API nie mają automatycznego mechanizmu do wysyłania części tokenu innej niż cookie. Implementacja prawdopodobnie zależy od implementacji kodu klienta. Poniżej przedstawiono kilka przykładów:

Przykład na poziomie klasy:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Przykład globalny:

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

Zastępowanie atrybutów globalnych lub atrybutów antyforgery kontrolera

Filtr IgnoreAntiforgeryToken służy do eliminowania potrzeby tokenu antyforgery dla danej akcji (lub kontrolera). Po zastosowaniu ten filtr zastępuje ValidateAntiForgeryToken i AutoValidateAntiforgeryToken filtry określone na wyższym poziomie (globalnie lub na kontrolerze).

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

    return RedirectToAction();
}

Odświeżanie tokenów po uwierzytelnieniu

Tokeny powinny być odświeżane po uwierzytelnieniu użytkownika poprzez przekierowanie użytkownika do widoku lub strony Razor.

JavaScript, AJAX i SPAs

W tradycyjnych aplikacjach opartych na kodzie HTML tokeny antyforgeryjne są przekazywane do serwera przy użyciu ukrytych pól formularza. W nowoczesnych aplikacjach opartych na języku JavaScript i usługach SPA wiele żądań jest wysyłanych programowo. Te żądania AJAX mogą używać innych technik (takich jak nagłówki żądań lub pliki cookie) w celu wysłania tokenu.

Jeśli pliki cookie są używane do przechowywania tokenów uwierzytelniania i uwierzytelniania żądań interfejsu API na serwerze, csrF jest potencjalnym problemem. Jeśli magazyn lokalny jest używany do przechowywania tokenu, luka w zabezpieczeniach CSRF może zostać usunięta, ponieważ wartości z magazynu lokalnego nie są wysyłane automatycznie do serwera z każdym żądaniem. Używanie pamięci lokalnej do przechowywania tokenu antyforgery na kliencie i wysyłanie tego tokenu jako nagłówka żądania jest zalecanym podejściem.

JavaScript

Przy użyciu języka JavaScript z widokami token można utworzyć przy użyciu usługi z poziomu widoku. Wstrzyknij usługę IAntiforgery do widoku i wywołaj 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>
}

W poprzednim przykładzie użyto języka JavaScript do odczytania ukrytej wartości pola nagłówka AJAX POST.

Takie podejście eliminuje konieczność bezpośredniego czynienia z ustawianiem plików cookie z serwera lub odczytywaniem ich z klienta. Jednak kiedy iniekcja usługi IAntiforgery nie jest możliwa, JavaScript może również uzyskać dostęp do tokenu w plikach cookie, uzyskanych z dodatkowego żądania do serwera (zazwyczaj same-origin), i użyć zawartości cookie, aby utworzyć nagłówek z wartością tokenu.

Zakładając, że skrypt wysyła token w nagłówku żądania o nazwie X-XSRF-TOKEN, skonfiguruj usługę antyforgery, aby wyszukać nagłówek X-XSRF-TOKEN.

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

Poniższy przykład dodaje chroniony punkt końcowy, który zapisze token żądania w formacie czytelnym dla JavaScript: 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();

W poniższym przykładzie użyto języka JavaScript do utworzenia żądania AJAX w celu uzyskania tokenu i wykonania innego żądania z odpowiednim nagłówkiem:

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

Uwierzytelnianie systemu Windows i pliki cookie ochrony przed fałszerzami

W przypadku korzystania z uwierzytelniania systemu Windows punkty końcowe aplikacji muszą być chronione przed atakami CSRF w taki sam sposób, jak w przypadku plików cookie. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera, dlatego punkty końcowe muszą być chronione przed atakami CSRF.

Rozszerz zabezpieczenia przed fałszerstwem

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie zachowania systemu chroniącego przed CSRF przez zaokrąglenie dodatkowych danych w każdym tokenie. Metoda GetAdditionalData jest wywoływana za każdym razem, gdy generowany jest token pola, a wartość zwracana jest osadzona w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, wybierać losową wartość lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData w celu weryfikacji tych danych, gdy token zostanie zweryfikowany. Nazwa użytkownika klienta jest już osadzona w wygenerowanych tokenach, więc nie ma potrzeby dołączania tych informacji. Jeśli token zawiera dane uzupełniające, ale IAntiForgeryAdditionalDataProvider nie jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby

Fałszowanie żądań między witrynami (znane również jako XSRF lub CSRF) to atak na aplikacje webowe, w którym złośliwa aplikacja internetowa wpływa na interakcję między przeglądarką klienta a aplikacją internetową, która ufa tej przeglądarce. Te ataki są możliwe, ponieważ przeglądarki internetowe automatycznie wysyłają niektóre typy tokenów uwierzytelniania z każdym żądaniem do witryny internetowej. Ta forma wykorzystania jest również znana jako atak jednym kliknięciem lub przejęcie sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika.

Przykład ataku CSRF:

  1. Użytkownik loguje się do www.good-banking-site.example.com za pomocą uwierzytelniania formularzy. Serwer uwierzytelnia użytkownika i wystawia odpowiedź zawierającą uwierzytelnianie cookie. Witryna jest podatna na ataki, ponieważ ufa wszelkim żądaniom otrzymanym przy użyciu prawidłowego uwierzytelniania cookie.

  2. Użytkownik odwiedza złośliwą witrynę. www.bad-crook-site.example.com

    Złośliwa witryna www.bad-crook-site.example.com, zawiera formularz HTML podobny do następującego przykładu:

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

    Zwróć uwagę, że formularz action przesyła dane do witryny podatnej na zagrożenia, a nie do złośliwej witryny. Jest to część CSRF związaną z "między stronami".

  3. Użytkownik wybierze przycisk Prześlij. Przeglądarka wysyła żądanie i automatycznie dołącza uwierzytelnianie cookie dla żądanej domeny. www.good-banking-site.example.com

  4. Żądanie jest uruchamiane na www.good-banking-site.example.com serwerze z kontekstem uwierzytelniania użytkownika i może wykonać dowolną akcję, którą może wykonać uwierzytelniony użytkownik.

Oprócz scenariusza, w którym użytkownik wybiera przycisk do przesłania formularza, złośliwa witryna może:

  • Uruchom skrypt, który automatycznie przesyła formularz.
  • Wyślij formularz jako żądanie AJAX.
  • Ukryj formularz przy użyciu arkusza CSS.

Te alternatywne scenariusze nie wymagają żadnej akcji ani danych wejściowych od użytkownika innego niż początkowo odwiedzanie złośliwej witryny.

Korzystanie z protokołu HTTPS nie zapobiega atakowi CSRF. Złośliwa witryna może równie łatwo wysłać żądanie https://www.good-banking-site.example.com/, jak i niezabezpieczone żądanie.

Niektóre ataki są celem punktów końcowych, które odpowiadają na żądania GET, w takim przypadku tag obrazu może służyć do wykonania akcji. Ta forma ataku jest powszechna w witrynach forum, które zezwalają na obrazy, ale blokują język JavaScript. Aplikacje, które zmieniają stan żądań GET, w których zmieniane są zmienne lub zasoby, są narażone na złośliwe ataki. Żądania GET, które zmieniają stan, są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

Ataki CSRF są możliwe dla aplikacji internetowych, które używają plików cookie do uwierzytelniania, ponieważ:

  • Przeglądarki przechowują pliki cookie wystawione przez aplikację internetową.
  • Przechowywane pliki cookie obejmują pliki cookie sesji dla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie pliki cookie skojarzone z domeną do aplikacji internetowej, niezależnie od tego, jak żądanie do aplikacji zostało wygenerowane w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystywania plików cookie. Na przykład uwierzytelnianie podstawowe i Digest również są podatne na zagrożenia. Po zalogowaniu się użytkownika przy użyciu uwierzytelniania podstawowego lub szyfrowego przeglądarka automatycznie wysyła poświadczenia do momentu zakończenia sesji.

W tym kontekście sesja odnosi się do sesji po stronie klienta, podczas której użytkownik jest uwierzytelniany. Nie ma to związku z sesjami po stronie serwera lub ASP.NET Core Session Middleware.

Użytkownicy mogą chronić się przed lukami w zabezpieczeniach CSRF, stosując środki ostrożności:

  • Wyloguj się z aplikacji internetowych po zakończeniu korzystania z nich.
  • Okresowo usuwaj pliki cookie przeglądarki.

Jednak luki w zabezpieczeniach CSRF są zasadniczo problemem z aplikacją internetową, a nie użytkownikiem końcowym.

Podstawy uwierzytelniania

CookieUwierzytelnianie oparte na protokole jest popularną formą uwierzytelniania. Systemy uwierzytelniania oparte na tokenach rosną na popularności, szczególnie w przypadku aplikacji jednostronicowych (SPA).

Gdy użytkownik uwierzytelnia się przy użyciu nazwy użytkownika i hasła, zostaje mu wydany token zawierający bilet uwierzytelniania, który może służyć do uwierzytelniania i autoryzacji. Token jest przechowywany jako cookie element, który jest wysyłany z każdym żądaniem wysyłanym przez klienta. Generowanie i weryfikowanie tego cookie jest wykonywane przez Cookie middleware uwierzytelniające. Oprogramowanie pośredniczące serializuje podmiot zabezpieczeń użytkownika w zaszyfrowanym pliku cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje cookie, odtwarza podmiot zabezpieczeń i przypisuje go do właściwości HttpContext.User.

Uwierzytelnianie oparte na tokenach

Po uwierzytelnieniu użytkownika otrzymuje token (a nie token antyforgery). Token zawiera informacje o użytkowniku w postaci oświadczeń lub tokenu referencyjnego wskazującego aplikację na stan użytkownika utrzymywany w aplikacji. Gdy użytkownik próbuje uzyskać dostęp do zasobu wymagającego uwierzytelnienia, token jest wysyłany do aplikacji z dodatkowym nagłówkiem autoryzacyjnym w postaci tokenu Bearer. Takie podejście sprawia, że aplikacja jest bezstanowa. W każdym kolejnym żądaniu token jest przekazywany w żądaniu weryfikacji po stronie serwera. Ten token nie jest zaszyfrowany; jest zakodowany. Na serwerze token jest dekodowany w celu uzyskania dostępu do informacji. Aby wysłać token do kolejnych żądań, zapisz token w magazynie lokalnym przeglądarki. Nie obawiaj się luki w zabezpieczeniach CSRF, jeśli token jest przechowywany w magazynie lokalnym przeglądarki. CSRF jest problemem, gdy token jest przechowywany w obiekcie cookie. Aby uzyskać więcej informacji, zobacz problem na GitHub przykład kodu SPA dodaje dwa pliki cookie.

Wiele aplikacji hostowanych w jednej domenie

Współdzielone środowiska hostingu są narażone na porwanie sesji, logowanie CSRF i inne ataki.

Chociaż example1.contoso.net i example2.contoso.net są różnymi hostami, istnieje niejawna relacja zaufania między hostami w domenie *.contoso.net . Ta niejawna relacja zaufania umożliwia potencjalnie niezaufanym hostom wpływ na pliki cookie innych (zasady pochodzenia, które zarządzają żądaniami AJAX, nie muszą mieć zastosowania do plików cookie HTTP).

Ataki wykorzystujące pliki cookie zaufane między aplikacjami hostowanymi na tej samej domenie mogą być blokowane przez nieudostępnianie domen. Gdy każda aplikacja jest hostowana we własnej domenie, nie ma niejawnej cookie relacji zaufania do wykorzystania.

konfiguracja ochrony przed fałszerzami ASP.NET Core

Ostrzeżenie

ASP.NET Core implementuje ochronę przed fałszerzją przy użyciu ASP.NET Core Data Protection. Stos ochrony danych musi być skonfigurowany do pracy w farmie serwerów. Aby uzyskać więcej informacji, zobacz Konfigurowanie ochrony danych.

Oprogramowanie pośredniczące chroniące przed fałszerzami jest dodawane do kontenera iniekcji zależności, gdy w Startup.ConfigureServices zostaje wywołany jeden z następujących interfejsów API:

W programie ASP.NET Core 2.0 lub nowszym element FormTagHelper wprowadza tokeny antyforgery do elementów formularza HTML. Następujące znaczniki w Razor pliku automatycznie generują tokeny chroniące przed fałszerzami:

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

Podobnie, IHtmlHelper.BeginForm generuje domyślnie tokeny antyforgery, jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML odbywa się, gdy znacznik <form> zawiera atrybut method="post" i którykolwiek z poniższych warunków jest spełniony:

  • Atrybut akcji jest pusty (action="").
  • Atrybut akcji nie jest podany (<form method="post">).

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML można wyłączyć:

  • Jawnie wyłącz tokeny ochrony przed fałszerzami za pomocą atrybutu asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • Element formularza jest wykluczony z Pomocników Tagów przy użyciu symbolu ! opt-out.

    <!form method="post">
        ...
    </!form>
    
  • Usuń element FormTagHelper z widoku. Element FormTagHelper można usunąć z widoku, dodając następującą dyrektywę Razor do widoku:

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

Uwaga

Razor Strony są automatycznie chronione przed plikami XSRF/CSRF. Aby uzyskać więcej informacji, zobacz XSRF/CSRF i Razor Pages.

Najczęstszym podejściem do obrony przed atakami CSRF jest użycie wzorca tokenu synchronizatora (STP). Usługa STP jest używana, gdy użytkownik żąda strony z danymi formularza:

  1. Serwer wysyła token skojarzony z tożsamością bieżącego użytkownika do klienta.
  2. Klient wysyła token z powrotem do serwera w celu weryfikacji.
  3. Jeśli serwer otrzyma token, który nie jest zgodny z tożsamością uwierzytelnionego użytkownika, żądanie zostanie odrzucone.

Token jest unikatowy i nieprzewidywalny. Token może również służyć do zapewnienia prawidłowego sekwencjonowania serii żądań (na przykład zapewnienia sekwencji żądań strony 1 > strona 2 > strona 3). Wszystkie formularze w szablonach ASP.NET Core MVC i Razor Pages generują tokeny antyforgery. Poniższa para przykładów widoków generuje tokeny chroniące przed fałszerzami:

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

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

Jawnie dodaj token antyfałszujący do elementu <form> bez użycia pomocników tagów, korzystając z pomocnika HTML @Html.AntiForgeryToken.

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

W każdym z powyższych przypadków ASP.NET Core dodaje ukryte pole formularza podobne do następującego przykładu:

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

ASP.NET Core zawiera trzy filtry do pracy z tokenami antyforgeryjnymi:

Opcje ochrony przed fałszerzami

Dostosowywanie AntiforgeryOptions w programie Startup.ConfigureServices:

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

Ustaw właściwości ochrony przed fałszerzami Cookie przy użyciu właściwości CookieBuilder klasy, jak pokazano w poniższej tabeli.

Opcja Opis
Cookie Określa ustawienia używane do tworzenia plików cookie chroniących przed fałszerzami.
FormFieldName Nazwa pola ukrytego formularza używanego przez system antyforgery do renderowania tokenów antyforgeryjnych w widokach.
HeaderName Nazwa nagłówka używanego przez system antyforgery. Jeśli nullsystem uwzględnia tylko dane formularza.
SuppressXFrameOptionsHeader Określa, czy pomijać generowanie nagłówka X-Frame-Options . Domyślnie nagłówek jest generowany z wartością "SAMEORIGIN". Wartość domyślna to false.

Aby uzyskać więcej informacji, zobacz CookieAuthenticationOptions.

Konfigurowanie funkcji ochrony przed fałszerzami za pomocą funkcji IAntiforgery

IAntiforgery udostępnia interfejs API do konfigurowania funkcji ochrony przed fałszerstwami. IAntiforgery można zażądać w metodzie Configure klasy Startup.

W poniższym przykładzie:

  • Oprogramowanie pośredniczące ze strony głównej aplikacji służy do generowania tokenu antyforgeryjnego i wysyłania go w odpowiedzi jako cookie.
  • Token żądania jest wysyłany jako czytelny w JavaScript cookie z domyślną konwencją nazewnictwa opisaną w sekcji 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);
    });
}

Wymaganie weryfikacji antyfałszerskiej

ValidateAntiForgeryToken to filtr akcji, który można zastosować do pojedynczej akcji, kontrolera lub globalnie. Żądania wysyłane do akcji, które mają zastosowany ten filtr, są blokowane, chyba że żądanie zawiera prawidłowy token antyforgery.

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

Atrybut ValidateAntiForgeryToken wymaga tokenu dla żądań skierowanych do oznaczonych metod akcji, w tym żądań HTTP GET. ValidateAntiForgeryToken Jeśli atrybut jest stosowany na kontrolerach aplikacji, można go zastąpić atrybutem IgnoreAntiforgeryToken .

Uwaga

ASP.NET Core nie obsługuje automatycznego dodawania tokenów antyforgeryjnych do żądań GET.

Automatyczne weryfikowanie tokenów antyforgeryjnych tylko pod kątem niebezpiecznych metod HTTP

aplikacje ASP.NET Core nie generują tokenów antyforgeryjnych dla bezpiecznych metod HTTP (GET, HEAD, OPTIONS i TRACE). Zamiast szeroko stosować ValidateAntiForgeryToken atrybut, a następnie zastąpić go atrybutami IgnoreAntiforgeryToken , można użyć atrybutu AutoValidateAntiforgeryToken . Ten atrybut działa identycznie z atrybutem ValidateAntiForgeryToken , z tą różnicą, że nie wymaga tokenów dla żądań wykonanych przy użyciu następujących metod HTTP:

  • GET
  • GŁOWA
  • Opcje
  • TRACE

Zalecamy szerokie stosowanie AutoValidateAntiforgeryToken w scenariuszach innych niż interfejsy API. Ten atrybut zapewnia, że akcje POST są domyślnie chronione. Alternatywą jest ignorowanie tokenów antyforgeryjnych domyślnie, chyba że ValidateAntiForgeryToken jest stosowane do poszczególnych metod akcji. Jest bardziej prawdopodobne w tym scenariuszu, aby metoda akcji POST została pozostawiona bez ochrony przez pomyłkę, pozostawiając aplikację podatną na ataki CSRF. Wszystkie POST-y powinny wysłać token antyfałszywce.

Interfejsy API nie mają automatycznego mechanizmu wysyłania części tokenu, która nie jest cookie. Implementacja prawdopodobnie zależy od implementacji kodu klienta. Poniżej przedstawiono kilka przykładów:

Przykład na poziomie klasy:

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

Przykład globalny:

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

Zastępowanie atrybutów globalnych lub atrybutów antyforgery kontrolera

Filtr IgnoreAntiforgeryToken służy do eliminowania potrzeby tokenu antyforgery dla danej akcji (lub kontrolera). Po zastosowaniu ten filtr zastępuje ValidateAntiForgeryToken i AutoValidateAntiforgeryToken filtry określone na wyższym poziomie (globalnie lub na kontrolerze).

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

Odświeżanie tokenów po uwierzytelnieniu

Tokeny powinny być odświeżane po uwierzytelnieniu użytkownika poprzez przekierowanie go do widoku lub strony Razor Pages.

JavaScript, AJAX i SPAs

W tradycyjnych aplikacjach opartych na kodzie HTML tokeny antyforgeryjne są przekazywane do serwera przy użyciu ukrytych pól formularza. W nowoczesnych aplikacjach opartych na języku JavaScript i usługach SPA wiele żądań jest wysyłanych programowo. Te żądania AJAX mogą używać innych technik (takich jak nagłówki żądań lub pliki cookie) w celu wysłania tokenu.

Jeśli pliki cookie są używane do przechowywania tokenów uwierzytelniania i uwierzytelniania żądań interfejsu API na serwerze, csrF jest potencjalnym problemem. Jeśli magazyn lokalny jest używany do przechowywania tokenu, luka w zabezpieczeniach CSRF może zostać usunięta, ponieważ wartości z magazynu lokalnego nie są wysyłane automatycznie do serwera z każdym żądaniem. Używanie pamięci lokalnej do przechowywania tokenu chroniącego przed fałszerstwem na kliencie i wysyłania tokenu jako nagłówka żądania jest zalecane.

JavaScript

Przy użyciu języka JavaScript z widokami token można utworzyć przy użyciu usługi z poziomu widoku. Wstrzyknij usługę IAntiforgery do widoku i wywołaj 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>

Takie podejście eliminuje konieczność bezpośredniego czynienia z ustawianiem plików cookie z serwera lub odczytywaniem ich z klienta.

W poprzednim przykładzie użyto języka JavaScript do odczytania ukrytej wartości pola nagłówka AJAX POST.

Język JavaScript może również uzyskiwać dostęp do tokenów w plikach cookie i używać zawartości cookie do tworzenia nagłówka z wartością tokenu.

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

Zakładając, że skrypt żąda wysłania tokenu w nagłówku o nazwie X-CSRF-TOKEN, skonfiguruj usługę antyforgery, aby szukała nagłówka X-CSRF-TOKEN.

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

W poniższym przykładzie użyto języka JavaScript do utworzenia żądania AJAX z odpowiednim nagłówkiem:

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

Usługa AngularJS używa konwencji do rozwiązywania problemów CSRF. Jeśli serwer wysyła element cookie o nazwie XSRF-TOKEN, serwis AngularJS $http dodaje wartość cookie do nagłówka, gdy wysyła żądanie do serwera. Ten proces jest automatyczny. Klient nie musi jawnie ustawiać nagłówka. Nazwa nagłówka to X-XSRF-TOKEN. Serwer powinien wykryć ten nagłówek i zweryfikować jego zawartość.

Aby API ASP.NET Core działało zgodnie z tą konwencją przy uruchamianiu aplikacji:

  • Skonfiguruj aplikację, aby podać token w cookie nazwie XSRF-TOKEN.
  • Skonfiguruj usługę antyforgery, aby wyszukać nagłówek o nazwie X-XSRF-TOKEN, co jest domyślną nazwą nagłówka w Angular do wysyłania tokenu XSRF.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

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

        return next(context);
    });
}

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

Uwaga

Gdy token antyforgery jest udostępniany zarówno w nagłówku żądania, jak i w treści formularza, tylko token w nagłówku jest sprawdzany.

Uwierzytelnianie systemu Windows i pliki cookie ochrony przed fałszerzami

W przypadku korzystania z uwierzytelniania systemu Windows punkty końcowe aplikacji muszą być chronione przed atakami CSRF w taki sam sposób, jak w przypadku plików cookie. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera, dlatego punkty końcowe muszą być chronione przed atakami CSRF.

Rozszerzenie zapobiegania fałszerstwom

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie zachowania systemu chroniącego przed atakami CSRF poprzez przesyłanie dodatkowych danych w każdym tokenie. Metoda GetAdditionalData jest wywoływana za każdym razem, gdy generowany jest token pola, a wartość zwracana jest osadzona w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, nonce lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData w celu weryfikacji tych danych podczas weryfikacji tokenu. Nazwa użytkownika klienta jest już osadzona w wygenerowanych tokenach, więc nie ma potrzeby dołączania tych informacji. Jeśli token zawiera dane uzupełniające, ale nie skonfigurowano IAntiForgeryAdditionalDataProvider, dane te nie są weryfikowane.

Dodatkowe zasoby