Zapobieganie atakom fałszerzowania żądań między witrynami (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 wykorzystania jest również znana jako atak jednym kliknięciem lub jazda na sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika. Fałszerzość żądań między witrynami jest również znana jako XSRF lub CSRF.

Przykład ataku CSRF:

  1. Użytkownik loguje się przy www.good-banking-site.example.com 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://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

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

  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 wysłać https://www.good-banking-site.com/ żądanie tak łatwo, jak można wysłać 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 stanu zmiany są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

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

  • Przeglądarki przechowują cookiewystawione przez aplikację internetową.
  • Przechowywane cookies obejmują sesje cookiedla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie cookies skojarzone z domeną do aplikacji internetowej każde żądanie niezależnie od sposobu wygenerowania żądania do aplikacji w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystania cookies. Na przykład uwierzytelnianie podstawowe i szyfrowane jest również 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 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 wyczyść przeglądarkę cookie.

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, 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 jest cookie wykonywane za pomocą oprogramowania pośredniczącego Cookie uwierzytelniania. Oprogramowanie pośredniczące serializuje podmiot zabezpieczeń użytkownika w zaszyfrowanym pliku cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje cookieelement , ponownie utworzy podmiot zabezpieczeń i przypisuje podmiot zabezpieczeń do HttpContext.User właściwości .

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 elementu nośnego. 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 on 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 i pobranie go i użycie go jako token elementu nośnego zapewnia ochronę przed atakami CSRF. Jednak jeśli aplikacja jest podatna na wstrzyknięcie skryptu za pośrednictwem środowiska XSS lub zewnętrznego pliku JavaScript, osoba atakująca 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 cookieobiekcie . Aby uzyskać więcej informacji, zobacz przykładowy kod SPA problemu z usługą GitHub dodaje dwa cookies.

Wiele aplikacji hostowanych w jednej domenie

Współużytkowane środowiska hostingu 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 umożliwia potencjalnie niezaufanym hostom wpływ na siebie cookie(zasady tego samego źródła, które zarządzają żądaniami AJAX, nie muszą mieć zastosowania do żądań HTTP cookie).

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

Antiforgery in 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 (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 generuje tokeny antyforgery domyślnie, IHtmlHelper.BeginForm jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML odbywa się, gdy <form> tag zawiera method="post" atrybut i jedną z następujących wartości 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 zrezygnowany z pomocników tagów przy użyciu symbolu Pomocnika tagów !

    <!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 <form> elementu bez używania pomocników tagów z pomocnikiem @Html.AntiForgeryTokenHTML:

<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 with 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. Jeśli na przykład 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 antyforgery cookies.
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.

W celu uzyskania więcej informacji, zobacz następujący temat: 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 programie 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);
});

Powyższy przykład ustawia 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 usługa Angular zawiera wbudowaną cookie ochronę XSRF, która domyślnie odczytuje nazwę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, które oznacza, 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
  • HEAD
  • OPTIONS
  • TRACE

Zalecamy korzystanie z szerokiego AutoValidateAntiforgeryToken zastosowania 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 poSTs powinny wysłać token antyforgery.

Interfejsy API nie mają mechanizmu automatycznego wysyłania tokenu, którycookie nie jest częścią tokenu. 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 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 cookies, w celu wysłania tokenu.

Jeśli cookieserwery 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 magazynu lokalnego do przechowywania tokenu antyforgery na kliencie i wysyłania tokenu jako nagłówka żądania jest zalecane.

Blazor

Aby uzyskać więcej informacji, zobacz ASP.NET Core authentication and authorization (Uwierzytelnianie i autoryzacja na platformie 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ć metodę 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średniej obsługi ustawień cookiez serwera lub odczytywania ich z klienta. Jednak w przypadku iniekcji IAntiforgery usługi nie jest to możliwe, użyj języka JavaScript, aby uzyskać dostęp do tokenów w następujących cookiejęzykach:

  • Tokeny dostępu w dodatkowym żądaniu do serwera, zazwyczaj same-origin.
  • cookieUżyj zawartości elementu , 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ć X-XSRF-TOKEN nagłówek:

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 metodę AddAntiforgery i UseAntiforgery(IApplicationBuilder) zarejestruj usługi ochrony przed fałszerzami 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:

  • Nie powoduje zwarcie wykonywania pozostałej części potoku żądania.
  • Ustawia IAntiforgeryValidationFeature w httpContext.Features bieżącego żądania.

Token antyforgery jest weryfikowany tylko wtedy, gdy:

  • Punkt końcowy zawiera metadane implementowania IAntiforgeryMetadata , gdzie 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 włączeniu ręcznie oprogramowanie pośredniczące ochrony przed fałszertwem musi działać po uwierzytelnieniu i uwierzytelnieniu oprogramowania pośredniczącego, aby zapobiec odczytywaniu danych formularza, gdy użytkownik jest nieuwierzytelniony.

Domyślnie minimalne interfejsy API, które akceptują dane formularza, wymagają weryfikacji tokenu antyforgery.

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 antyugeryjny i wskazujący bool , 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 opublikuje następujące wpisy:

  • /todo wymaga prawidłowego tokenu antyforgery.
  • /todo2nie 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 do:

  • /todo z formularza wygenerowanego / przez punkt końcowy kończy się powodzeniem, ponieważ token antyforgery jest prawidłowy.
  • /todo z formularza wygenerowanego /SkipToken przez element kończy się niepowodzeniem, ponieważ antyforgery nie jest uwzględniona.
  • /todo2 z formularza wygenerowanego /DisableAntiforgery przez punkt końcowy kończy się powodzeniem, ponieważ antiforgery nie jest wymagany.
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 deweloperów zgłaszany jest wyjątek.
  • W środowisku produkcyjnym jest rejestrowany komunikat.

Uwierzytelnianie systemu Windows i antyforgery cookies

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 cookies. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera i punktów końcowych, które muszą być chronione przed atakami CSRF.

Rozszerzanie antyforgerii

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie zachowania systemu chroniącego przed CSRF przez zaokrąglenie dodatkowych danych w każdym tokenie. Metoda jest wywoływana GetAdditionalData za każdym razem, gdy jest generowany token pola, a wartość zwracana jest osadzona w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, wartość inną lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData metodę weryfikacji tych danych po zweryfikowaniu 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 IAntiForgeryAdditionalDataProvider jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby

Fałszerzacja żądań między witrynami (znana również jako XSRF lub CSRF) to atak na aplikacje hostowane w Internecie, w którym złośliwa aplikacja internetowa może mieć wpływ 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 jazda na sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika.

Przykład ataku CSRF:

  1. Użytkownik loguje się przy www.good-banking-site.example.com 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://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

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

  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 wysłać https://www.good-banking-site.com/ żądanie tak samo łatwo, jak może wysłać 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 stanu zmiany są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

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

  • Przeglądarki przechowują cookiewystawione przez aplikację internetową.
  • Przechowywane cookies obejmują sesje cookiedla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie cookies skojarzone z domeną do aplikacji internetowej każde żądanie niezależnie od sposobu wygenerowania żądania do aplikacji w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystania cookies. Na przykład uwierzytelnianie podstawowe i szyfrowane jest również 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 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 wyczyść przeglądarkę cookie.

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, wystawia 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 jest cookie wykonywane przez Cookie oprogramowanie pośredniczące uwierzytelniania. Oprogramowanie pośredniczące serializuje podmiot zabezpieczeń użytkownika w zaszyfrowanym pliku cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje cookieelement , ponownie utworzy podmiot zabezpieczeń i przypisuje podmiot zabezpieczeń do HttpContext.User właściwości .

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 elementu nośnego. 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 on 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 i pobranie go i użycie go jako token elementu nośnego zapewnia ochronę przed atakami CSRF. Jednak jeśli aplikacja jest podatna na wstrzyknięcie skryptu za pośrednictwem środowiska XSS lub zewnętrznego pliku javascript, osoba atakująca 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 cookieobiekcie . Aby uzyskać więcej informacji, zobacz przykładowy kod SPA problemu z usługą GitHub dodaje dwa cookies.

Wiele aplikacji hostowanych w jednej domenie

Współużytkowane ś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 siebie cookie(zasady tego samego źródła, które zarządzają żądaniami AJAX, nie muszą mieć zastosowania do żądań HTTP cookie).

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

Antiforgery in 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 generuje tokeny antyforgery domyślnie, IHtmlHelper.BeginForm jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML odbywa się, gdy <form> tag zawiera method="post" atrybut i jedną z następujących wartości 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 zrezygnowany z pomocników tagów przy użyciu symbolu Pomocnika tagów !

    <!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 <form> elementu bez używania pomocników tagów z pomocnikiem @Html.AntiForgeryTokenHTML:

<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 with 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. Jeśli na przykład 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 antyforgery cookies.
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.

W celu uzyskania więcej informacji, zobacz następujący temat: 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 programie 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);
});

Powyższy przykład ustawia 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 usługa Angular zawiera wbudowaną cookie ochronę XSRF, która domyślnie odczytuje nazwę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, które oznacza, 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
  • HEAD
  • OPTIONS
  • TRACE

Zalecamy korzystanie z szerokiego AutoValidateAntiforgeryToken zastosowania 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 poSTs powinny wysłać token antyforgery.

Interfejsy API nie mają mechanizmu automatycznego wysyłania tokenu, którycookie nie jest częścią tokenu. 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 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 cookies), aby wysłać token.

Jeśli cookieserwery 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 magazynu lokalnego do przechowywania tokenu antyforgery 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. Wstrzyknąć usługę IAntiforgery do widoku i wywołać metodę 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średniej obsługi ustawień cookiez serwera lub odczytywania ich z klienta. Jednak w przypadku iniekcji IAntiforgery usługi nie jest to możliwe, użyj języka JavaScript, aby uzyskać dostęp do tokenów w następujących cookiejęzykach:

  • Tokeny dostępu w dodatkowym żądaniu do serwera, zazwyczaj same-origin.
  • cookieUżyj zawartości elementu , 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ć X-XSRF-TOKEN nagłówek:

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

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

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 cookies. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera i punktów końcowych, które muszą być chronione przed atakami CSRF.

Rozszerzanie antyforgerii

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie zachowania systemu chroniącego przed CSRF przez zaokrąglenie dodatkowych danych w każdym tokenie. Metoda jest wywoływana GetAdditionalData za każdym razem, gdy jest generowany token pola, a wartość zwracana jest osadzona w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, wartość inną lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData metodę weryfikacji tych danych po zweryfikowaniu 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 IAntiForgeryAdditionalDataProvider jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby

Fałszerzacja żądań między witrynami (znana również jako XSRF lub CSRF) to atak na aplikacje hostowane w Internecie, w którym złośliwa aplikacja internetowa może mieć wpływ 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 jazda na sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika.

Przykład ataku CSRF:

  1. Użytkownik loguje się przy www.good-banking-site.example.com 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://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

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

  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 wysłać https://www.good-banking-site.com/ żądanie tak samo łatwo, jak może wysłać 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 stanu zmiany są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

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

  • Przeglądarki przechowują cookiewystawione przez aplikację internetową.
  • Przechowywane cookies obejmują sesje cookiedla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie cookies skojarzone z domeną do aplikacji internetowej każde żądanie niezależnie od sposobu wygenerowania żądania do aplikacji w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystania cookies. Na przykład uwierzytelnianie podstawowe i szyfrowane jest również 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 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 wyczyść przeglądarkę cookie.

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, wystawia 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 jest cookie wykonywane przez Cookie oprogramowanie pośredniczące uwierzytelniania. Oprogramowanie pośredniczące serializuje podmiot zabezpieczeń użytkownika w zaszyfrowanym pliku cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje cookieelement , ponownie utworzy podmiot zabezpieczeń i przypisuje podmiot zabezpieczeń do HttpContext.User właściwości .

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 elementu nośnego. 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 on 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 cookieobiekcie . Aby uzyskać więcej informacji, zobacz przykładowy kod SPA problemu z usługą GitHub dodaje dwa cookies.

Wiele aplikacji hostowanych w jednej domenie

Współużytkowane ś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 siebie cookie(zasady tego samego źródła, które zarządzają żądaniami AJAX, nie muszą mieć zastosowania do żądań HTTP cookie).

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

Antiforgery in 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 generuje tokeny antyforgery domyślnie, IHtmlHelper.BeginForm jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML odbywa się, gdy <form> tag zawiera method="post" atrybut i jedną z następujących wartości 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 zrezygnowany z pomocników tagów przy użyciu symbolu Pomocnika tagów !

    <!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 <form> elementu bez używania pomocników tagów z pomocnikiem @Html.AntiForgeryTokenHTML:

<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 with 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. Jeśli na przykład 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 antyforgery cookies.
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.

W celu uzyskania więcej informacji, zobacz następujący temat: 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 programie 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);
});

Powyższy przykład ustawia 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 usługa Angular zawiera wbudowaną cookie ochronę XSRF, która domyślnie odczytuje nazwę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, które oznacza, 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
  • HEAD
  • OPTIONS
  • TRACE

Zalecamy korzystanie z szerokiego AutoValidateAntiforgeryToken zastosowania 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 poSTs powinny wysłać token antyforgery.

Interfejsy API nie mają mechanizmu automatycznego wysyłania tokenu, którycookie nie jest częścią tokenu. 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 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 cookies), aby wysłać token.

Jeśli cookieserwery 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 magazynu lokalnego do przechowywania tokenu antyforgery 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. Wstrzyknąć usługę IAntiforgery do widoku i wywołać metodę 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średniej obsługi ustawień cookiez serwera lub odczytywania ich z klienta. Jednak w przypadku iniekcji IAntiforgery usługi nie jest możliwe, język JavaScript może również uzyskać dostęp do tokenu w plikach s cookieuzyskanych z dodatkowego żądania do serwera (zwykle same-origin) i użyć cookiezawartości elementu , 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ć X-XSRF-TOKEN nagłówek:

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

Poniższy przykład dodaje chroniony punkt końcowy, który zapisze token żądania do kodu JavaScript z możliwością cookieodczytu:

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

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 cookies. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera, dlatego punkty końcowe muszą być chronione przed atakami CSRF.

Rozszerzanie antyforgerii

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie zachowania systemu chroniącego przed CSRF przez zaokrąglenie dodatkowych danych w każdym tokenie. Metoda jest wywoływana GetAdditionalData za każdym razem, gdy jest generowany token pola, a wartość zwracana jest osadzona w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, wartość inną lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData metodę weryfikacji tych danych po zweryfikowaniu 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 IAntiForgeryAdditionalDataProvider jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby

Fałszerzacja żądań między witrynami (znana również jako XSRF lub CSRF) to atak na aplikacje hostowane w Internecie, w którym złośliwa aplikacja internetowa może mieć wpływ 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 jazda na sesji, ponieważ atak korzysta z wcześniej uwierzytelnionej sesji użytkownika.

Przykład ataku CSRF:

  1. Użytkownik loguje się przy www.good-banking-site.example.com 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://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

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

  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 wysłać https://www.good-banking-site.com/ żądanie tak samo łatwo, jak może wysłać 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 stanu zmiany są niezabezpieczone. Najlepszym rozwiązaniem jest nigdy nie zmiana stanu żądania GET.

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

  • Przeglądarki przechowują cookiewystawione przez aplikację internetową.
  • Przechowywane cookies obejmują sesje cookiedla uwierzytelnionych użytkowników.
  • Przeglądarki wysyłają wszystkie cookies skojarzone z domeną do aplikacji internetowej każde żądanie niezależnie od sposobu wygenerowania żądania do aplikacji w przeglądarce.

Jednak ataki CSRF nie są ograniczone do wykorzystania cookies. Na przykład uwierzytelnianie podstawowe i szyfrowane jest również 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 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 wyczyść przeglądarkę cookie.

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, wystawia 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 jest cookie wykonywane przez Cookie oprogramowanie pośredniczące uwierzytelniania. Oprogramowanie pośredniczące serializuje podmiot zabezpieczeń użytkownika w zaszyfrowanym pliku cookie. W kolejnych żądaniach oprogramowanie pośredniczące weryfikuje cookieelement , ponownie utworzy podmiot zabezpieczeń i przypisuje podmiot zabezpieczeń do HttpContext.User właściwości .

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 elementu nośnego. 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 on 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 cookieobiekcie . Aby uzyskać więcej informacji, zobacz przykładowy kod SPA problemu z usługą GitHub dodaje dwa cookies.

Wiele aplikacji hostowanych w jednej domenie

Współużytkowane ś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 siebie cookie(zasady tego samego źródła, które zarządzają żądaniami AJAX, nie muszą mieć zastosowania do żądań HTTP cookie).

Ataki wykorzystujące zaufane cookieusługi między aplikacjami hostowanymi w tej samej domenie mogą być blokowane przez nieudzielenie 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 wstrzykiwania zależności, gdy jeden z następujących interfejsów API jest wywoływany w pliku Startup.ConfigureServices:

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 generuje tokeny antyforgery domyślnie, IHtmlHelper.BeginForm jeśli metoda formularza nie jest GET.

Automatyczne generowanie tokenów antyforgeryjnych dla elementów formularza HTML odbywa się, gdy <form> tag zawiera method="post" atrybut i jedną z następujących wartości 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 zrezygnowany z pomocników tagów przy użyciu symbolu Pomocnika tagów !

    <!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 antyforgery do <form> elementu bez używania pomocników tagów z pomocnikiem @Html.AntiForgeryTokenHTML:

<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 antyforgery cookies.
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.

W celu uzyskania więcej informacji, zobacz następujący temat: 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 Configure metodzie Startup klasy .

W poniższym przykładzie:

  • Oprogramowanie pośredniczące ze strony głównej aplikacji służy do generowania tokenu chroniącego przed fałszowaniem i wysyłania go w odpowiedzi jako cookie.
  • Token żądania jest wysyłany jako czytelny cookie dla języka JavaScript z domyślną konwencją nazewnictwa angular 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 ochrony przed fałszerzami

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ń do metod akcji, które oznacza, 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
  • HEAD
  • OPTIONS
  • TRACE

Zalecamy korzystanie z szerokiego AutoValidateAntiforgeryToken zastosowania 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 poSTs powinny wysłać token antyforgery.

Interfejsy API nie mają mechanizmu automatycznego wysyłania tokenu, którycookie nie jest częścią tokenu. 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 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 cookies), aby wysłać token.

Jeśli cookieserwery 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 magazynu lokalnego do przechowywania tokenu antyforgery 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. Wstrzyknąć usługę IAntiforgery do widoku i wywołać metodę 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średniej obsługi ustawień cookiez serwera lub odczytywania 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 cookiejęzykach s i używać cookiejej do tworzenia nagłówka z wartością tokenu.

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

Przy założeniu, że skrypt żąda wysłania tokenu w nagłówku o nazwie X-CSRF-TOKEN, skonfiguruj usługę antyforgery, aby wyszukać X-CSRF-TOKEN nagłówek:

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

KątoweJS

Platforma AngularJS używa konwencji do adresowania CSRF. Jeśli serwer wysyła cookie element o nazwie XSRF-TOKEN, usługa AngularJS$http dodaje cookie wartość do nagłówka podczas wysyłania żądania 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 ASP.NET Core API pracować z tą konwencją podczas uruchamiania aplikacji:

  • Skonfiguruj aplikację, aby podać token w cookie nazwie XSRF-TOKEN.
  • Skonfiguruj usługę antyforgery, aby wyszukać nagłówek o nazwie X-XSRF-TOKEN, który jest domyślną nazwą nagłówka 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 ładunku formularza, tylko token w nagłówku jest weryfikowany.

Uwierzytelnianie systemu Windows i antyforgery cookies

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 cookies. Przeglądarka niejawnie wysyła kontekst uwierzytelniania do serwera, dlatego punkty końcowe muszą być chronione przed atakami CSRF.

Rozszerzanie antyforgerii

Typ IAntiforgeryAdditionalDataProvider umożliwia deweloperom rozszerzenie zachowania systemu chroniącego przed CSRF przez zaokrąglenie dodatkowych danych w każdym tokenie. Metoda jest wywoływana GetAdditionalData za każdym razem, gdy jest generowany token pola, a wartość zwracana jest osadzona w wygenerowanym tokenie. Implementator może zwrócić znacznik czasu, wartość inną lub dowolną inną wartość, a następnie wywołać ValidateAdditionalData metodę weryfikacji tych danych po zweryfikowaniu 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 IAntiForgeryAdditionalDataProvider jest skonfigurowany, dane uzupełniające nie są weryfikowane.

Dodatkowe zasoby