Éviter les attaques de falsification de demande intersites (XSRF/CSRF) dans ASP.NET Core

Par Fiyaz Hasan et Rick Anderson

La falsification de requêtes intersites est une attaque contre les applications hébergées sur le Web par laquelle une application web malveillante peut influencer l’interaction entre un navigateur client et une application web qui fait confiance à ce navigateur. Ces attaques sont possibles car les navigateurs Web envoient automatiquement certains types de jetons d'authentification à chaque requête adressée à un site Web. Cette forme d'exploit est également connue sous le nom d'attaque en un clic ou de chevauchement de session, car l'attaque tire parti de la session précédemment authentifiée de l'utilisateur. La falsification de requête intersites est également appelée XSRF ou CSRF.

Un exemple d'attaque CSRF :

  1. Un utilisateur se connecte www.good-banking-site.example.com à l'aide de l'authentification par formulaire. Le serveur authentifie l'utilisateur et émet une réponse qui inclut une authentification cookie. Le site est vulnérable aux attaques car il fait confiance à toute requête qu'il reçoit avec une authentification valide cookie.

  2. L'utilisateur visite un site malveillant, www.bad-crook-site.example.com.

    Le site malveillant, www.bad-crook-site.example.com, contient un formulaire HTML similaire à l'exemple suivant :

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

    Notez que les publications du formulaire action sur le site vulnérable, pas sur le site malveillant. Il s'agit de la partie "intersites" de CSRF.

  3. L'utilisateur sélectionne le bouton Soumettre. Le navigateur fait la demande et inclut automatiquement l'authentification cookie pour le domaine demandé, www.good-banking-site.example.com.

  4. La requête s'exécute sur le serveur www.good-banking-site.example.com avec le contexte d'authentification de l'utilisateur et peut effectuer toute action qu'un utilisateur authentifié est autorisé à effectuer.

En plus du scénario où l'utilisateur sélectionne le bouton pour soumettre le formulaire, le site malveillant pourrait :

  • Exécutez un script qui soumet automatiquement le formulaire.
  • Envoyez la soumission du formulaire en tant que requête AJAX.
  • Masquez le formulaire à l'aide de CSS.

Ces scénarios alternatifs ne nécessitent aucune action ou entrée de la part de l'utilisateur autre que la visite initiale du site malveillant.

L'utilisation de HTTPS n'empêche pas une attaque CSRF. Le site malveillant peut envoyer une requête https://www.good-banking-site.com/ aussi facilement qu’il peut envoyer une requête non sécurisée.

Certaines attaques ciblent les endpoints qui répondent aux requêtes GET, auquel cas une balise d'image peut être utilisée pour effectuer l'action. Cette forme d'attaque est courante sur les sites de forum qui autorisent les images mais bloquent JavaScript. Les applications qui changent d'état sur les requêtes GET, où des variables ou des ressources sont modifiées, sont vulnérables aux attaques malveillantes. Les requêtes GET qui changent d'état ne sont pas sécurisées. Une bonne pratique consiste à ne jamais modifier l'état d'une requête GET.

Les attaques CSRF sont possibles contre les applications Web qui utilisent cookies pour l'authentification car :

  • Les navigateurs stockent les cookies émis par une application Web.
  • Les cookies stockés incluent les sessions cookies pour les utilisateurs authentifiés.
  • Les navigateurs envoient tous les cookies associés à un domaine à l'application Web à chaque requête, quelle que soit la manière dont la demande à l'application a été générée dans le navigateur.

Cependant, les attaques CSRF ne se limitent pas à exploiter cookies. Par exemple, l'authentification De base et Digest sont également vulnérables. Une fois qu'un utilisateur s'est connecté avec l'authentification De base ou Digest, le navigateur envoie automatiquement les informations d'identification jusqu'à la fin de la session.

Dans ce contexte, la session fait référence à la session côté client au cours de laquelle l'utilisateur est authentifié. Il n'est pas lié aux sessions côté serveur ou au middleware de session ASP.NET Core.

Les utilisateurs peuvent se prémunir contre les vulnérabilités CSRF en prenant des précautions :

  • Déconnectez-vous des applications Web lorsque vous avez fini de les utiliser.
  • Effacez périodiquement les navigateurs cookies.

Cependant, les vulnérabilités CSRF sont fondamentalement un problème avec l'application Web, pas avec l'utilisateur final.

Concepts de base de l’authentification

Cookie-authentification basée sur est une forme d'authentification populaire. Les systèmes d'authentification basés sur des jetons gagnent en popularité, en particulier pour les applications à page unique (SPA).

Lorsqu'un utilisateur s'authentifie à l'aide de son nom d'utilisateur et de son mot de passe, il reçoit un jeton contenant un ticket d'authentification. Le jeton peut être utilisé pour l’authentification et l’autorisation. Le jeton est stocké sous la forme d'un cookie qui est envoyé avec chaque requête faite par le client. La génération et la validation de cookie sont effectuées avec l’intergiciel d’authentification Cookie. Le middleware sérialise un principal d'utilisateur dans un fichier cookie. Lors des requêtes suivantes, le middleware valide le cookie, recrée le principal et attribue le principal à la propriété HttpContext.User.

Authentification basée sur un jeton

Lorsqu'un utilisateur est authentifié, il reçoit un jeton (et non un jeton anti-contrefaçon). Le jeton contient des informations sur l'utilisateur sous la forme de revendications ou d'un jeton de référence qui pointe l'application vers l'état de l'utilisateur maintenu dans l'application. Lorsqu'un utilisateur tente d'accéder à une ressource nécessitant une authentification, le jeton est envoyé à l'application avec un en-tête d'autorisation supplémentaire sous la forme d'un jeton Bearer. Cette approche rend l'application sans état. Dans chaque demande suivante, le jeton est transmis dans la requête de validation côté serveur. Ce token n'est pas chiffré; c'est encodé. Sur le serveur, le jeton est décodé pour accéder à ses informations. Pour envoyer le jeton lors de requêtes ultérieures, stockez le jeton dans le stockage local du navigateur. Placer un jeton dans le stockage local du navigateur, le récupérer et l'utiliser comme jeton porteur offre une protection contre les attaques CSRF. Cependant, si l’application est vulnérable à l’injection de script via XSS ou un fichier JavaScript externe compromis, un attaquant peut récupérer n’importe quelle valeur du stockage local et se l’envoyer. ASP.NET Core code par défaut toutes les sorties côté serveur à partir de variables, ce qui réduit le risque de XSS. Si vous remplacez ce comportement en utilisant Html.Raw ou un code personnalisé avec une entrée non fiable, vous pouvez augmenter le risque de XSS.

Ne vous inquiétez pas de la vulnérabilité CSRF si le jeton est stocké dans le stockage local du navigateur. CSRF est un problème lorsque le jeton est stocké dans un fichier cookie. Pour plus d'informations, consultez l'exemple de code SPA du problème GitHub ajoute deux cookies.

Plusieurs applications hébergées sur un domaine

Les environnements d’hébergement partagé sont vulnérables au piratage de session, à la connexion CSRF et à d’autres attaques.

Bien que example1.contoso.net et example2.contoso.net soient des hôtes différents, il existe une relation d'approbation implicite entre les hôtes du domaine *.contoso.net. Cette relation de confiance implicite permet à des hôtes potentiellement non approuvés d'affecter les cookies les uns des autres (les politiques de même origine qui régissent les requêtes AJAX ne s'appliquent pas nécessairement aux HTTP cookies).

Les attaques qui exploitent les cookies de confiance entre les applications hébergées sur le même domaine peuvent être évitées en ne partageant pas les domaines. Lorsque chaque application est hébergée sur son propre domaine, il n'y a pas de relation de confiance implicite cookie à exploiter.

Anti-contrefaçon dans ASP.NET Core

Avertissement

ASP.NET Core implémente l'anti-contrefaçon à l'aide de ASP.NET Core Data Protection. La pile de protection des données doit être configurée pour fonctionner dans une batterie de serveurs. Pour plus d'informations, voir Configuration de la protection des données.

Le middleware anti-contrefaçon est ajouté au conteneur d'injection de dépendances lorsque l'une des API suivantes est appelée dans Program.cs :

Pour plus d’informations, consultez Anti-falsification avec des API minimales.

FormTagHelper injecte des jetons antifalsification dans les éléments de formulaire HTML. Le balisage suivant dans un fichier Razor génère automatiquement des jetons anti-contrefaçon :

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

De même, IHtmlHelper.BeginForm génère des jetons anti-contrefaçon par défaut si la méthode du formulaire n'est pas GET.

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML se produit lorsque la balise <form> contient l'attribut method="post" et que l'une des conditions suivantes est vraie :

  • L'attribut action est vide (action="").
  • L'attribut action n'est pas fourni (<form method="post">).

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML peut être désactivée :

  • Désactivez explicitement les jetons anti-contrefaçon avec l'attribut asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • L'élément de formulaire est désactivé des Tag Helpers en utilisant le Tag Helper ! symbole d'exclusion :

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Supprimez le FormTagHelper de la vue. Le FormTagHelper peut être supprimé d'une vue en ajoutant la directive suivante à la vue Razor :

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

Note

Razor Pages sont automatiquement protégées contre XSRF/CSRF. Pour plus d'informations, voir XSRF/CSRF Razor et Pages.

L'approche la plus courante pour se défendre contre les attaques CSRF consiste à utiliser le Synchronizer Token Pattern (STP). STP est utilisé lorsque l'utilisateur demande une page avec des données de formulaire :

  1. Le serveur envoie un jeton associé à l'identité de l'utilisateur actuel au client.
  2. Le client renvoie le jeton au serveur pour vérification.
  3. Si le serveur reçoit un jeton qui ne correspond pas à l'identité de l'utilisateur authentifié, la requête est rejetée.

Le jeton est unique et imprévisible. Le jeton peut également être utilisé pour assurer le bon séquencement d'une série de requêtes (par exemple, assurer la séquence de requête de : page 1 > page 2 > page 3). Tous les formulaires des modèles ASP.NET Core MVC et Pages Razor génèrent des jetons anti-contrefaçon. La paire d'exemples de vue suivante génère des jetons anti-contrefaçon :

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

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

Ajoutez explicitement un jeton anti-contrefaçon à un élément <form> sans utiliser les Tag Helpers avec le helper HTML @Html.AntiForgeryToken :

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

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

Dans chacun des cas précédents, ASP.NET Core ajoute un champ de formulaire masqué similaire à l'exemple suivant :

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

ASP.NET Core inclut trois filtres pour travailler avec des jetons anti-contrefaçon :

Anti-contrefaçon avec AddControllers

L'appel AddControllers n'active pas les jetons anti-contrefaçon. AddControllersWithViews doit être appelé pour avoir une prise en charge intégrée des jetons anti-contrefaçon.

Plusieurs onglets de navigateur et le modèle de jeton de synchronisation

Avec le modèle de jeton de synchronisation, seule la page la plus récemment chargée contient un jeton anti-contrefaçon valide. L'utilisation de plusieurs onglets peut être problématique. Par exemple, si un utilisateur ouvre plusieurs onglets :

  • Seul l'onglet chargé le plus récemment contient un jeton anti-contrefaçon valide.
  • Les requêtes effectuées à partir d'onglets précédemment chargés échouent avec une erreur : Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Envisagez d'autres modèles de protection CSRF si cela pose un problème.

Configurer l'anti-contrefaçon avec AntiforgeryOptions

Personnaliser AntiforgeryOptions en Program.cs :

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

Définissez les propriétés Cookie anti-contrefaçon à l'aide des propriétés de la classe CookieBuilder, comme indiqué dans le tableau suivant.

Option Description
Cookie Détermine les paramètres utilisés pour créer les cookies anti-contrefaçons.
FormFieldName Le nom du champ de formulaire masqué utilisé par le système anti-contrefaçon pour rendre les jetons anti-contrefaçon dans les vues.
HeaderName Le nom de l'en-tête utilisé par le système anti-contrefaçon. Si null, le système ne prend en compte que les données du formulaire.
SuppressXFrameOptionsHeader Spécifie s'il faut supprimer la génération de X-Frame-Options en-tête. Par défaut, l'en-tête est généré avec une valeur de "SAMEORIGIN". La valeur par défaut est false.

Pour plus d’informations, voir CookieAuthenticationOptions.

Générez des jetons anti-contrefaçon avec IAntiforgery

IAntiforgery fournit l'API pour configurer les fonctionnalités anti-contrefaçon. IAntiforgery peut être demandé en Program.cs à l’aide de WebApplication.Services. L'exemple suivant utilise le middleware de la page d'accueil de l'application pour générer un jeton anti-contrefaçon et l'envoyer dans la réponse en tant que 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);
});

L'exemple précédent définit un cookie nommé XSRF-TOKEN. Le client peut le lire cookie et fournir sa valeur sous forme d'en-tête attaché aux requêtes AJAX. Par exemple, Angular inclut une protection XSRF intégrée qui lit un cookie nommé XSRF-TOKEN par défaut.

Exiger une validation anti-contrefaçon

Le filtre d'action ValidateAntiForgeryToken peut être appliqué à une action individuelle, à un contrôleur ou globalement. Les requêtes adressées aux actions auxquelles ce filtre est appliqué sont bloquées, sauf si la requête inclut un jeton anti-contrefaçon valide :

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

    return RedirectToAction();
}

L'attribut ValidateAntiForgeryToken requiert un jeton pour les requêtes aux méthodes d'action qu'il marque, y compris les requêtes HTTP GET. Si l'attribut ValidateAntiForgeryToken est appliqué sur les contrôleurs de l'application, il peut être remplacé par l'attribut IgnoreAntiforgeryToken.

Valider automatiquement les jetons anti-contrefaçon pour les méthodes HTTP non sécurisées uniquement

Au lieu d'appliquer largement l'attribut ValidateAntiForgeryToken, puis de le remplacer par des attributs IgnoreAntiforgeryToken, l'attribut AutoValidateAntiforgeryToken peut être utilisé. Cet attribut fonctionne de la même manière que l'attribut ValidateAntiForgeryToken, sauf qu'il ne nécessite pas de jetons pour les requêtes effectuées à l'aide des méthodes HTTP suivantes :

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Nous vous recommandons d'utiliser AutoValidateAntiforgeryToken largement pour les scénarios non API. Cet attribut garantit que les actions POST sont protégées par défaut. L'alternative consiste à ignorer les jetons anti-contrefaçon par défaut, sauf si ValidateAntiForgeryToken cela s'applique à des méthodes d'action individuelles. Dans ce scénario, il est plus probable qu'une méthode d'action POST ne soit pas protégée par erreur, laissant l'application vulnérable aux attaques CSRF. Tous les POST doivent envoyer le jeton anti-contrefaçon.

Les API n'ont pas de mécanisme automatique pour envoyer la non-cookie partie du jeton. L'implémentation dépend probablement de l'implémentation du code client. Quelques exemples sont présentés ci-dessous :

Exemple au niveau de la classe :

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Exemple global :

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

Remplacer les attributs anti-contrefaçon globaux ou du contrôleur

Le filtre IgnoreAntiforgeryToken est utilisé pour éliminer le besoin d'un jeton anti-contrefaçon pour une action (ou contrôleur) donnée. Lorsqu'il est appliqué, ce filtre remplace ValidateAntiForgeryToken et AutoValidateAntiforgeryToken filtre les spécifications à un niveau supérieur (globalement ou sur un contrôleur).

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

    return RedirectToAction();
}

Actualiser les jetons après l'authentification

Les jetons doivent être actualisés une fois l'utilisateur authentifié en le redirigeant vers une vue ou une page Pages Razor.

JavaScript, AJAX et SPA

Dans les applications HTML traditionnelles, les jetons anti-contrefaçon sont transmis au serveur à l'aide de champs de formulaire masqués. Dans les applications et les SPA modernes basés sur JavaScript, de nombreuses demandes sont effectuées par programmation. Ces requêtes AJAX peuvent utiliser d’autres techniques, telles que des en-têtes de demande ou des cookies, pour envoyer le jeton.

Si les cookies sont utilisés pour stocker des jetons d'authentification et pour authentifier les demandes d'API sur le serveur, CSRF est un problème potentiel. Si le stockage local est utilisé pour stocker le jeton, la vulnérabilité CSRF peut être atténuée car les valeurs du stockage local ne sont pas envoyées automatiquement au serveur à chaque requête. L'utilisation du stockage local pour stocker le jeton anti-contrefaçon sur le client et l'envoi du jeton en tant qu'en-tête de requête est une approche recommandée.

Blazor

Pour plus d’informations, consultez Authentification et autorisation ASP.NET Core Blazor.

JavaScript

En utilisant JavaScript avec des vues, le jeton peut être créé à l'aide d'un service à partir de la vue. Injectez le service IAntiforgery dans la vue et appelez 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>
}

L'exemple précédent utilise JavaScript pour lire la valeur du champ masqué pour l'en-tête AJAX POST.

Cette approche élimine le besoin de traiter directement les paramètres cookies du serveur ou de les lire depuis le client. Cependant, lorsque l'injection du service IAntiforgery n'est pas possible, utilisez JavaScript pour accéder aux jetons dans cookies :

  • Accéder aux jetons dans une requête supplémentaire au serveur, généralement same-origin.
  • Utilisez le contenu de cookies pour créer un en-tête avec la valeur du jeton.

En supposant que le script envoie le jeton dans un en-tête de requête appelé X-XSRF-TOKEN, configurez le service anti-contrefaçon pour rechercher X-XSRF-TOKEN en-tête :

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

L'exemple suivant ajoute un point de terminaison protégé qui écrit le jeton de requête dans un fichier JavaScript lisible cookie :

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

L'exemple suivant utilise JavaScript pour effectuer une requête AJAX afin d'obtenir le jeton et effectuer une autre requête avec l'en-tête approprié :

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

Note

Lorsque le jeton anti-contrefaçon est fourni dans l’en-tête de requête et dans la charge utile du formulaire, seul le jeton de l’en-tête est validé.

Anti-contrefaçon avec des API minimales

Appelez AddAntiforgery et UseAntiforgery(IApplicationBuilder) pour inscrire des services d’anti-falsification dans DI. Les jetons d’antifalsification sont utilisés pour atténuer les attaques de falsification de requête intersites.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

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

app.Run();

L’intergiciel d’antifalsification :

Le jeton d’antifalsification n’est validé que si :

  • Le point de terminaison contient des métadonnées implémentant IAntiforgeryMetadataRequiresValidation=true.
  • La méthode HTTP associée au point de terminaison est une méthode HTTP pertinente. Les méthodes pertinentes sont toutes les méthodes HTTP, à l’exception de TRACE, OPTIONS, HEAD et GET.
  • La requête est associée à un point de terminaison valide.

Remarque : lorsqu’il est activé manuellement, l’intergiciel d’antifalsification doit s’exécuter après l’authentification et l’intergiciel d’autorisation pour empêcher la lecture des données de formulaire lorsque l’utilisateur n’est pas authentifié.

Par défaut, les API minimales qui acceptent les données de formulaires nécessitent une validation de jeton d’antifalsification.

Considérez la méthode GenerateForm suivante :

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

Le code précédent comporte trois arguments, l’action, le jeton d’antifalsification et un bool indiquant si le jeton doit être utilisé.

Considérez l’exemple de suivant :

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

Dans le code précédent, les publications sur :

  • /todo nécessitent un jeton d’antifalsification valide.
  • /todo2 ne nécessitent pas de jeton d’antifalsification valide, car DisableAntiforgery est appelé.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

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

Une publication sur :

  • /todo à partir du formulaire généré par le point de terminaison / réussit, car le jeton d’antifalsification est valide.
  • /todo à partir du formulaire généré par le /SkipToken échoue, car l’antifalsification n’est pas incluse.
  • /todo2 à partir du formulaire généré par le point de terminaison /DisableAntiforgery réussit, car l’antifalsification n’est pas obligatoire.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

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

Lorsqu’un formulaire est envoyé sans jeton d’antifalsification valide :

  • Dans l’environnement de développement, une exception est levée.
  • Dans l’environnement de production, un message est journalisé.

Authentification Windows et anti-contrefaçon cookies

Lors de l'utilisation de l'authentification Windows, les points de terminaison d'application doivent être protégés contre les attaques CSRF de la même manière que pour cookies. Le navigateur envoie implicitement le contexte d'authentification au serveur et les terminaux doivent être protégés contre les attaques CSRF.

Étendre l'anti-contrefaçon

Le type IAntiforgeryAdditionalDataProvider permet aux développeurs d'étendre le comportement du système anti-CSRF en effectuant des allers-retours de données supplémentaires dans chaque jeton. La méthode GetAdditionalData est appelée chaque fois qu'un jeton de champ est généré et la valeur de retour est intégrée dans le jeton généré. Un implémenteur peut renvoyer un horodatage, un nonce ou toute autre valeur, puis appeler ValidateAdditionalData pour valider ces données lorsque le jeton est validé. Le nom d'utilisateur du client est déjà intégré dans les jetons générés, il n'est donc pas nécessaire d'inclure ces informations. Si un jeton inclut des données supplémentaires mais qu'aucune IAntiForgeryAdditionalDataProvider n'est configurée, les données supplémentaires ne sont pas validées.

Ressources supplémentaires

La falsification de requêtes intersites (également connue sous le nom de XSRF ou CSRF) est une attaque contre les applications hébergées sur le Web par laquelle une application Web malveillante peut influencer l'interaction entre un navigateur client et une application Web qui fait confiance à ce navigateur. Ces attaques sont possibles car les navigateurs Web envoient automatiquement certains types de jetons d'authentification à chaque requête adressée à un site Web. Cette forme d'exploit est également connue sous le nom d'attaque en un clic ou de chevauchement de session, car l'attaque tire parti de la session précédemment authentifiée de l'utilisateur.

Un exemple d'attaque CSRF :

  1. Un utilisateur se connecte www.good-banking-site.example.com à l'aide de l'authentification par formulaire. Le serveur authentifie l'utilisateur et émet une réponse qui inclut une authentification cookie. Le site est vulnérable aux attaques car il fait confiance à toute requête qu'il reçoit avec une authentification valide cookie.

  2. L'utilisateur visite un site malveillant, www.bad-crook-site.example.com.

    Le site malveillant, www.bad-crook-site.example.com, contient un formulaire HTML similaire à l'exemple suivant :

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

    Notez que les publications du formulaire action sur le site vulnérable, pas sur le site malveillant. Il s'agit de la partie "intersites" de CSRF.

  3. L'utilisateur sélectionne le bouton Soumettre. Le navigateur fait la demande et inclut automatiquement l'authentification cookie pour le domaine demandé, www.good-banking-site.example.com.

  4. La requête s'exécute sur le serveur www.good-banking-site.example.com avec le contexte d'authentification de l'utilisateur et peut effectuer toute action qu'un utilisateur authentifié est autorisé à effectuer.

En plus du scénario où l'utilisateur sélectionne le bouton pour soumettre le formulaire, le site malveillant pourrait :

  • Exécutez un script qui soumet automatiquement le formulaire.
  • Envoyez la soumission du formulaire en tant que requête AJAX.
  • Masquez le formulaire à l'aide de CSS.

Ces scénarios alternatifs ne nécessitent aucune action ou entrée de la part de l'utilisateur autre que la visite initiale du site malveillant.

L'utilisation de HTTPS n'empêche pas une attaque CSRF. Le site malveillant peut envoyer une requête https://www.good-banking-site.com/ aussi facilement qu'il peut envoyer une requête non sécurisée.

Certaines attaques ciblent les endpoints qui répondent aux requêtes GET, auquel cas une balise d'image peut être utilisée pour effectuer l'action. Cette forme d'attaque est courante sur les sites de forum qui autorisent les images mais bloquent JavaScript. Les applications qui changent d'état sur les requêtes GET, où des variables ou des ressources sont modifiées, sont vulnérables aux attaques malveillantes. Les requêtes GET qui changent d'état ne sont pas sécurisées. Une bonne pratique consiste à ne jamais modifier l'état d'une requête GET.

Les attaques CSRF sont possibles contre les applications Web qui utilisent cookies pour l'authentification car :

  • Les navigateurs stockent les cookies émis par une application Web.
  • Les cookies stockés incluent les sessions cookies pour les utilisateurs authentifiés.
  • Les navigateurs envoient tous les cookies associés à un domaine à l'application Web à chaque requête, quelle que soit la manière dont la demande à l'application a été générée dans le navigateur.

Cependant, les attaques CSRF ne se limitent pas à exploiter cookies. Par exemple, l'authentification De base et Digest sont également vulnérables. Une fois qu'un utilisateur s'est connecté avec l'authentification De base ou Digest, le navigateur envoie automatiquement les informations d'identification jusqu'à la fin de la session.

Dans ce contexte, la session fait référence à la session côté client au cours de laquelle l'utilisateur est authentifié. Il n'est pas lié aux sessions côté serveur ou au middleware de session ASP.NET Core.

Les utilisateurs peuvent se prémunir contre les vulnérabilités CSRF en prenant des précautions :

  • Déconnectez-vous des applications Web lorsque vous avez fini de les utiliser.
  • Effacez périodiquement les navigateurs cookies.

Cependant, les vulnérabilités CSRF sont fondamentalement un problème avec l'application Web, pas avec l'utilisateur final.

Concepts de base de l’authentification

Cookie-authentification basée sur est une forme d'authentification populaire. Les systèmes d'authentification basés sur des jetons gagnent en popularité, en particulier pour les applications à page unique (SPA).

Lorsqu'un utilisateur s'authentifie à l'aide de son nom d'utilisateur et de son mot de passe, il reçoit un jeton contenant un ticket d'authentification pouvant être utilisé pour l'authentification et l'autorisation. Le jeton est stocké sous la forme d'un cookie qui est envoyé avec chaque requête faite par le client. La génération et la validation de cookie sont effectuées par le middleware d'authentification Cookie. Le middleware sérialise un principal d'utilisateur dans un fichier cookie. Lors des requêtes suivantes, le middleware valide le cookie, recrée le principal et attribue le principal à la propriété HttpContext.User.

Authentification basée sur un jeton

Lorsqu'un utilisateur est authentifié, il reçoit un jeton (et non un jeton anti-contrefaçon). Le jeton contient des informations sur l'utilisateur sous la forme de revendications ou d'un jeton de référence qui pointe l'application vers l'état de l'utilisateur maintenu dans l'application. Lorsqu'un utilisateur tente d'accéder à une ressource nécessitant une authentification, le jeton est envoyé à l'application avec un en-tête d'autorisation supplémentaire sous la forme d'un jeton Bearer. Cette approche rend l'application sans état. Dans chaque demande suivante, le jeton est transmis dans la requête de validation côté serveur. Ce token n'est pas chiffré; c'est encodé. Sur le serveur, le jeton est décodé pour accéder à ses informations. Pour envoyer le jeton lors de requêtes ultérieures, stockez le jeton dans le stockage local du navigateur. Placer un jeton dans le stockage local du navigateur, le récupérer et l'utiliser comme jeton porteur offre une protection contre les attaques CSRF. Cependant, si l'application était vulnérable à l'injection de script via XSS ou un fichier javascript externe compromis, un attaquant pourrait récupérer n'importe quelle valeur du stockage local et se l'envoyer. ASP.NET Core code par défaut toutes les sorties côté serveur à partir de variables, ce qui réduit le risque de XSS. Si vous remplacez ce comportement en utilisant Html.Raw ou un code personnalisé avec une entrée non fiable, vous pouvez augmenter le risque de XSS.

Ne vous inquiétez pas de la vulnérabilité CSRF si le jeton est stocké dans le stockage local du navigateur. CSRF est un problème lorsque le jeton est stocké dans un fichier cookie. Pour plus d'informations, consultez l'exemple de code SPA du problème GitHub ajoute deux cookies.

Plusieurs applications hébergées sur un domaine

Les environnements d'hébergement partagé sont vulnérables au piratage de session, à la connexion CSRF et à d'autres attaques.

Bien que example1.contoso.net et example2.contoso.net soient des hôtes différents, il existe une relation d'approbation implicite entre les hôtes du domaine *.contoso.net. Cette relation de confiance implicite permet à des hôtes potentiellement non approuvés d'affecter les cookies les uns des autres (les politiques de même origine qui régissent les requêtes AJAX ne s'appliquent pas nécessairement aux HTTP cookies).

Les attaques qui exploitent les cookies de confiance entre les applications hébergées sur le même domaine peuvent être évitées en ne partageant pas les domaines. Lorsque chaque application est hébergée sur son propre domaine, il n'y a pas de relation de confiance implicite cookie à exploiter.

Anti-contrefaçon dans ASP.NET Core

Avertissement

ASP.NET Core implémente l'anti-contrefaçon à l'aide de ASP.NET Core Data Protection. La pile de protection des données doit être configurée pour fonctionner dans une batterie de serveurs. Pour plus d'informations, voir Configuration de la protection des données.

Le middleware anti-contrefaçon est ajouté au conteneur d'injection de dépendances lorsque l'une des API suivantes est appelée dans Program.cs :

FormTagHelper injecte des jetons antifalsification dans les éléments de formulaire HTML. Le balisage suivant dans un fichier Razor génère automatiquement des jetons anti-contrefaçon :

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

De même, IHtmlHelper.BeginForm génère des jetons anti-contrefaçon par défaut si la méthode du formulaire n'est pas GET.

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML se produit lorsque la balise <form> contient l'attribut method="post" et que l'une des conditions suivantes est vraie :

  • L'attribut action est vide (action="").
  • L'attribut action n'est pas fourni (<form method="post">).

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML peut être désactivée :

  • Désactivez explicitement les jetons anti-contrefaçon avec l'attribut asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • L'élément de formulaire est désactivé des Tag Helpers en utilisant le Tag Helper ! symbole d'exclusion :

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Supprimez le FormTagHelper de la vue. Le FormTagHelper peut être supprimé d'une vue en ajoutant la directive suivante à la vue Razor :

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

Note

Razor Pages sont automatiquement protégées contre XSRF/CSRF. Pour plus d'informations, voir XSRF/CSRF Razor et Pages.

L'approche la plus courante pour se défendre contre les attaques CSRF consiste à utiliser le Synchronizer Token Pattern (STP). STP est utilisé lorsque l'utilisateur demande une page avec des données de formulaire :

  1. Le serveur envoie un jeton associé à l'identité de l'utilisateur actuel au client.
  2. Le client renvoie le jeton au serveur pour vérification.
  3. Si le serveur reçoit un jeton qui ne correspond pas à l'identité de l'utilisateur authentifié, la requête est rejetée.

Le jeton est unique et imprévisible. Le jeton peut également être utilisé pour assurer le bon séquencement d'une série de requêtes (par exemple, assurer la séquence de requête de : page 1 > page 2 > page 3). Tous les formulaires des modèles ASP.NET Core MVC et Pages Razor génèrent des jetons anti-contrefaçon. La paire d'exemples de vue suivante génère des jetons anti-contrefaçon :

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

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

Ajoutez explicitement un jeton anti-contrefaçon à un élément <form> sans utiliser les Tag Helpers avec le helper HTML @Html.AntiForgeryToken :

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

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

Dans chacun des cas précédents, ASP.NET Core ajoute un champ de formulaire masqué similaire à l'exemple suivant :

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

ASP.NET Core inclut trois filtres pour travailler avec des jetons anti-contrefaçon :

Anti-contrefaçon avec AddControllers

L'appel AddControllers n'active pas les jetons anti-contrefaçon. AddControllersWithViews doit être appelé pour avoir une prise en charge intégrée des jetons anti-contrefaçon.

Plusieurs onglets de navigateur et le modèle de jeton de synchronisation

Avec le modèle de jeton de synchronisation, seule la page la plus récemment chargée contient un jeton anti-contrefaçon valide. L'utilisation de plusieurs onglets peut être problématique. Par exemple, si un utilisateur ouvre plusieurs onglets :

  • Seul l'onglet chargé le plus récemment contient un jeton anti-contrefaçon valide.
  • Les requêtes effectuées à partir d'onglets précédemment chargés échouent avec une erreur : Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Envisagez d'autres modèles de protection CSRF si cela pose un problème.

Configurer l'anti-contrefaçon avec AntiforgeryOptions

Personnaliser AntiforgeryOptions en Program.cs :

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

Définissez les propriétés Cookie anti-contrefaçon à l'aide des propriétés de la classe CookieBuilder, comme indiqué dans le tableau suivant.

Option Description
Cookie Détermine les paramètres utilisés pour créer les cookies anti-contrefaçons.
FormFieldName Le nom du champ de formulaire masqué utilisé par le système anti-contrefaçon pour rendre les jetons anti-contrefaçon dans les vues.
HeaderName Le nom de l'en-tête utilisé par le système anti-contrefaçon. Si null, le système ne prend en compte que les données du formulaire.
SuppressXFrameOptionsHeader Spécifie s'il faut supprimer la génération de X-Frame-Options en-tête. Par défaut, l'en-tête est généré avec une valeur de "SAMEORIGIN". La valeur par défaut est false.

Pour plus d’informations, voir CookieAuthenticationOptions.

Générez des jetons anti-contrefaçon avec IAntiforgery

IAntiforgery fournit l'API pour configurer les fonctionnalités anti-contrefaçon. IAntiforgery peut être demandé en Program.cs à l’aide de WebApplication.Services. L'exemple suivant utilise le middleware de la page d'accueil de l'application pour générer un jeton anti-contrefaçon et l'envoyer dans la réponse en tant que 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);
});

L'exemple précédent définit un cookie nommé XSRF-TOKEN. Le client peut le lire cookie et fournir sa valeur sous forme d'en-tête attaché aux requêtes AJAX. Par exemple, Angular inclut une protection XSRF intégrée qui lit un cookie nommé XSRF-TOKEN par défaut.

Exiger une validation anti-contrefaçon

Le filtre d'action ValidateAntiForgeryToken peut être appliqué à une action individuelle, à un contrôleur ou globalement. Les requêtes adressées aux actions auxquelles ce filtre est appliqué sont bloquées, sauf si la requête inclut un jeton anti-contrefaçon valide :

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

    return RedirectToAction();
}

L'attribut ValidateAntiForgeryToken requiert un jeton pour les requêtes aux méthodes d'action qu'il marque, y compris les requêtes HTTP GET. Si l'attribut ValidateAntiForgeryToken est appliqué sur les contrôleurs de l'application, il peut être remplacé par l'attribut IgnoreAntiforgeryToken.

Valider automatiquement les jetons anti-contrefaçon pour les méthodes HTTP non sécurisées uniquement

Au lieu d'appliquer largement l'attribut ValidateAntiForgeryToken, puis de le remplacer par des attributs IgnoreAntiforgeryToken, l'attribut AutoValidateAntiforgeryToken peut être utilisé. Cet attribut fonctionne de la même manière que l'attribut ValidateAntiForgeryToken, sauf qu'il ne nécessite pas de jetons pour les requêtes effectuées à l'aide des méthodes HTTP suivantes :

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Nous vous recommandons d'utiliser AutoValidateAntiforgeryToken largement pour les scénarios non API. Cet attribut garantit que les actions POST sont protégées par défaut. L'alternative consiste à ignorer les jetons anti-contrefaçon par défaut, sauf si ValidateAntiForgeryToken cela s'applique à des méthodes d'action individuelles. Dans ce scénario, il est plus probable qu'une méthode d'action POST ne soit pas protégée par erreur, laissant l'application vulnérable aux attaques CSRF. Tous les POST doivent envoyer le jeton anti-contrefaçon.

Les API n'ont pas de mécanisme automatique pour envoyer la non-cookie partie du jeton. L'implémentation dépend probablement de l'implémentation du code client. Quelques exemples sont présentés ci-dessous :

Exemple au niveau de la classe :

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Exemple global :

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

Remplacer les attributs anti-contrefaçon globaux ou du contrôleur

Le filtre IgnoreAntiforgeryToken est utilisé pour éliminer le besoin d'un jeton anti-contrefaçon pour une action (ou contrôleur) donnée. Lorsqu'il est appliqué, ce filtre remplace ValidateAntiForgeryToken et AutoValidateAntiforgeryToken filtre les spécifications à un niveau supérieur (globalement ou sur un contrôleur).

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

    return RedirectToAction();
}

Actualiser les jetons après l'authentification

Les jetons doivent être actualisés une fois l'utilisateur authentifié en le redirigeant vers une vue ou une page Pages Razor.

JavaScript, AJAX et SPA

Dans les applications HTML traditionnelles, les jetons anti-contrefaçon sont transmis au serveur à l'aide de champs de formulaire masqués. Dans les applications et les SPA modernes basés sur JavaScript, de nombreuses demandes sont effectuées par programmation. Ces requêtes AJAX peuvent utiliser d'autres techniques (telles que des en-têtes de requête ou des cookies) pour envoyer le jeton.

Si les cookies sont utilisés pour stocker des jetons d'authentification et pour authentifier les demandes d'API sur le serveur, CSRF est un problème potentiel. Si le stockage local est utilisé pour stocker le jeton, la vulnérabilité CSRF peut être atténuée car les valeurs du stockage local ne sont pas envoyées automatiquement au serveur à chaque requête. L'utilisation du stockage local pour stocker le jeton anti-contrefaçon sur le client et l'envoi du jeton en tant qu'en-tête de requête est une approche recommandée.

JavaScript

En utilisant JavaScript avec des vues, le jeton peut être créé à l'aide d'un service à partir de la vue. Injectez le service IAntiforgery dans la vue et appelez 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>
}

L'exemple précédent utilise JavaScript pour lire la valeur du champ masqué pour l'en-tête AJAX POST.

Cette approche élimine le besoin de traiter directement les paramètres cookies du serveur ou de les lire depuis le client. Cependant, lorsque l'injection du service IAntiforgery n'est pas possible, utilisez JavaScript pour accéder aux jetons dans cookies :

  • Accéder aux jetons dans une requête supplémentaire au serveur, généralement same-origin.
  • Utilisez le contenu de cookies pour créer un en-tête avec la valeur du jeton.

En supposant que le script envoie le jeton dans un en-tête de requête appelé X-XSRF-TOKEN, configurez le service anti-contrefaçon pour rechercher X-XSRF-TOKEN en-tête :

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

L'exemple suivant ajoute un point de terminaison protégé qui écrit le jeton de requête dans un fichier JavaScript lisible cookie :

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

L'exemple suivant utilise JavaScript pour effectuer une requête AJAX afin d'obtenir le jeton et effectuer une autre requête avec l'en-tête approprié :

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

Note

Lorsque le jeton anti-contrefaçon est fourni dans l’en-tête de requête et dans la charge utile du formulaire, seul le jeton de l’en-tête est validé.

Anti-contrefaçon avec des API minimales

Minimal APIs ne prend pas en charge l'utilisation des filtres inclus (ValidateAntiForgeryToken, AutoValidateAntiforgeryToken, IgnoreAntiforgeryToken), mais IAntiforgery fournit les API requises pour valider une requête.

L'exemple suivant crée un filtre qui valide le jeton anti-contrefaçon :

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

        });
    }
}

Le filtre peut ensuite être appliqué à un point de terminaison :

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

Authentification Windows et anti-contrefaçon cookies

Lors de l'utilisation de l'authentification Windows, les points de terminaison d'application doivent être protégés contre les attaques CSRF de la même manière que pour cookies. Le navigateur envoie implicitement le contexte d'authentification au serveur et les terminaux doivent être protégés contre les attaques CSRF.

Étendre l'anti-contrefaçon

Le type IAntiforgeryAdditionalDataProvider permet aux développeurs d'étendre le comportement du système anti-CSRF en effectuant des allers-retours de données supplémentaires dans chaque jeton. La méthode GetAdditionalData est appelée chaque fois qu'un jeton de champ est généré et la valeur de retour est intégrée dans le jeton généré. Un implémenteur peut renvoyer un horodatage, un nonce ou toute autre valeur, puis appeler ValidateAdditionalData pour valider ces données lorsque le jeton est validé. Le nom d'utilisateur du client est déjà intégré dans les jetons générés, il n'est donc pas nécessaire d'inclure ces informations. Si un jeton inclut des données supplémentaires mais qu'aucune IAntiForgeryAdditionalDataProvider n'est configurée, les données supplémentaires ne sont pas validées.

Ressources supplémentaires

La falsification de requêtes intersites (également connue sous le nom de XSRF ou CSRF) est une attaque contre les applications hébergées sur le Web par laquelle une application Web malveillante peut influencer l'interaction entre un navigateur client et une application Web qui fait confiance à ce navigateur. Ces attaques sont possibles car les navigateurs Web envoient automatiquement certains types de jetons d'authentification à chaque requête adressée à un site Web. Cette forme d'exploit est également connue sous le nom d'attaque en un clic ou de chevauchement de session, car l'attaque tire parti de la session précédemment authentifiée de l'utilisateur.

Un exemple d'attaque CSRF :

  1. Un utilisateur se connecte www.good-banking-site.example.com à l'aide de l'authentification par formulaire. Le serveur authentifie l'utilisateur et émet une réponse qui inclut une authentification cookie. Le site est vulnérable aux attaques car il fait confiance à toute requête qu'il reçoit avec une authentification valide cookie.

  2. L'utilisateur visite un site malveillant, www.bad-crook-site.example.com.

    Le site malveillant, www.bad-crook-site.example.com, contient un formulaire HTML similaire à l'exemple suivant :

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

    Notez que les publications du formulaire action sur le site vulnérable, pas sur le site malveillant. Il s'agit de la partie "intersites" de CSRF.

  3. L'utilisateur sélectionne le bouton Soumettre. Le navigateur fait la demande et inclut automatiquement l'authentification cookie pour le domaine demandé, www.good-banking-site.example.com.

  4. La requête s'exécute sur le serveur www.good-banking-site.example.com avec le contexte d'authentification de l'utilisateur et peut effectuer toute action qu'un utilisateur authentifié est autorisé à effectuer.

En plus du scénario où l'utilisateur sélectionne le bouton pour soumettre le formulaire, le site malveillant pourrait :

  • Exécutez un script qui soumet automatiquement le formulaire.
  • Envoyez la soumission du formulaire en tant que requête AJAX.
  • Masquez le formulaire à l'aide de CSS.

Ces scénarios alternatifs ne nécessitent aucune action ou entrée de la part de l'utilisateur autre que la visite initiale du site malveillant.

L'utilisation de HTTPS n'empêche pas une attaque CSRF. Le site malveillant peut envoyer une requête https://www.good-banking-site.com/ aussi facilement qu'il peut envoyer une requête non sécurisée.

Certaines attaques ciblent les endpoints qui répondent aux requêtes GET, auquel cas une balise d'image peut être utilisée pour effectuer l'action. Cette forme d'attaque est courante sur les sites de forum qui autorisent les images mais bloquent JavaScript. Les applications qui changent d'état sur les requêtes GET, où des variables ou des ressources sont modifiées, sont vulnérables aux attaques malveillantes. Les requêtes GET qui changent d'état ne sont pas sécurisées. Une bonne pratique consiste à ne jamais modifier l'état d'une requête GET.

Les attaques CSRF sont possibles contre les applications Web qui utilisent cookies pour l'authentification car :

  • Les navigateurs stockent les cookies émis par une application Web.
  • Les cookies stockés incluent les sessions cookies pour les utilisateurs authentifiés.
  • Les navigateurs envoient tous les cookies associés à un domaine à l'application Web à chaque requête, quelle que soit la manière dont la demande à l'application a été générée dans le navigateur.

Cependant, les attaques CSRF ne se limitent pas à exploiter cookies. Par exemple, l'authentification De base et Digest sont également vulnérables. Une fois qu'un utilisateur s'est connecté avec l'authentification De base ou Digest, le navigateur envoie automatiquement les informations d'identification jusqu'à la fin de la session.

Dans ce contexte, la session fait référence à la session côté client au cours de laquelle l'utilisateur est authentifié. Il n'est pas lié aux sessions côté serveur ou au middleware de session ASP.NET Core.

Les utilisateurs peuvent se prémunir contre les vulnérabilités CSRF en prenant des précautions :

  • Déconnectez-vous des applications Web lorsque vous avez fini de les utiliser.
  • Effacez périodiquement les navigateurs cookies.

Cependant, les vulnérabilités CSRF sont fondamentalement un problème avec l'application Web, pas avec l'utilisateur final.

Concepts de base de l’authentification

Cookie-authentification basée sur est une forme d'authentification populaire. Les systèmes d'authentification basés sur des jetons gagnent en popularité, en particulier pour les applications à page unique (SPA).

Lorsqu'un utilisateur s'authentifie à l'aide de son nom d'utilisateur et de son mot de passe, il reçoit un jeton contenant un ticket d'authentification pouvant être utilisé pour l'authentification et l'autorisation. Le jeton est stocké sous la forme d'un cookie qui est envoyé avec chaque requête faite par le client. La génération et la validation de cookie sont effectuées par le middleware d'authentification Cookie. Le middleware sérialise un principal d'utilisateur dans un fichier cookie. Lors des requêtes suivantes, le middleware valide le cookie, recrée le principal et attribue le principal à la propriété HttpContext.User.

Authentification basée sur un jeton

Lorsqu'un utilisateur est authentifié, il reçoit un jeton (et non un jeton anti-contrefaçon). Le jeton contient des informations sur l'utilisateur sous la forme de revendications ou d'un jeton de référence qui pointe l'application vers l'état de l'utilisateur maintenu dans l'application. Lorsqu'un utilisateur tente d'accéder à une ressource nécessitant une authentification, le jeton est envoyé à l'application avec un en-tête d'autorisation supplémentaire sous la forme d'un jeton Bearer. Cette approche rend l'application sans état. Dans chaque demande suivante, le jeton est transmis dans la requête de validation côté serveur. Ce token n'est pas chiffré; c'est encodé. Sur le serveur, le jeton est décodé pour accéder à ses informations. Pour envoyer le jeton lors de requêtes ultérieures, stockez le jeton dans le stockage local du navigateur. Ne vous inquiétez pas de la vulnérabilité CSRF si le jeton est stocké dans le stockage local du navigateur. CSRF est un problème lorsque le jeton est stocké dans un fichier cookie. Pour plus d'informations, consultez l'exemple de code SPA du problème GitHub ajoute deux cookies.

Plusieurs applications hébergées sur un domaine

Les environnements d'hébergement partagé sont vulnérables au piratage de session, à la connexion CSRF et à d'autres attaques.

Bien que example1.contoso.net et example2.contoso.net soient des hôtes différents, il existe une relation d'approbation implicite entre les hôtes du domaine *.contoso.net. Cette relation de confiance implicite permet à des hôtes potentiellement non approuvés d'affecter les cookies les uns des autres (les politiques de même origine qui régissent les requêtes AJAX ne s'appliquent pas nécessairement aux HTTP cookies).

Les attaques qui exploitent les cookies de confiance entre les applications hébergées sur le même domaine peuvent être évitées en ne partageant pas les domaines. Lorsque chaque application est hébergée sur son propre domaine, il n'y a pas de relation de confiance implicite cookie à exploiter.

Anti-contrefaçon dans ASP.NET Core

Avertissement

ASP.NET Core implémente l'anti-contrefaçon à l'aide de ASP.NET Core Data Protection. La pile de protection des données doit être configurée pour fonctionner dans une batterie de serveurs. Pour plus d'informations, voir Configuration de la protection des données.

Le middleware anti-contrefaçon est ajouté au conteneur d'injection de dépendances lorsque l'une des API suivantes est appelée dans Program.cs :

FormTagHelper injecte des jetons antifalsification dans les éléments de formulaire HTML. Le balisage suivant dans un fichier Razor génère automatiquement des jetons anti-contrefaçon :

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

De même, IHtmlHelper.BeginForm génère des jetons anti-contrefaçon par défaut si la méthode du formulaire n'est pas GET.

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML se produit lorsque la balise <form> contient l'attribut method="post" et que l'une des conditions suivantes est vraie :

  • L'attribut action est vide (action="").
  • L'attribut action n'est pas fourni (<form method="post">).

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML peut être désactivée :

  • Désactivez explicitement les jetons anti-contrefaçon avec l'attribut asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • L'élément de formulaire est désactivé des Tag Helpers en utilisant le Tag Helper ! symbole d'exclusion :

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Supprimez le FormTagHelper de la vue. Le FormTagHelper peut être supprimé d'une vue en ajoutant la directive suivante à la vue Razor :

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

Note

Razor Pages sont automatiquement protégées contre XSRF/CSRF. Pour plus d'informations, voir XSRF/CSRF Razor et Pages.

L'approche la plus courante pour se défendre contre les attaques CSRF consiste à utiliser le Synchronizer Token Pattern (STP). STP est utilisé lorsque l'utilisateur demande une page avec des données de formulaire :

  1. Le serveur envoie un jeton associé à l'identité de l'utilisateur actuel au client.
  2. Le client renvoie le jeton au serveur pour vérification.
  3. Si le serveur reçoit un jeton qui ne correspond pas à l'identité de l'utilisateur authentifié, la requête est rejetée.

Le jeton est unique et imprévisible. Le jeton peut également être utilisé pour assurer le bon séquencement d'une série de requêtes (par exemple, assurer la séquence de requête de : page 1 > page 2 > page 3). Tous les formulaires des modèles ASP.NET Core MVC et Pages Razor génèrent des jetons anti-contrefaçon. La paire d'exemples de vue suivante génère des jetons anti-contrefaçon :

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

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

Ajoutez explicitement un jeton anti-contrefaçon à un élément <form> sans utiliser les Tag Helpers avec le helper HTML @Html.AntiForgeryToken :

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

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

Dans chacun des cas précédents, ASP.NET Core ajoute un champ de formulaire masqué similaire à l'exemple suivant :

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

ASP.NET Core inclut trois filtres pour travailler avec des jetons anti-contrefaçon :

Anti-contrefaçon avec AddControllers

L'appel AddControllers n'active pas les jetons anti-contrefaçon. AddControllersWithViews doit être appelé pour avoir une prise en charge intégrée des jetons anti-contrefaçon.

Plusieurs onglets de navigateur et le modèle de jeton de synchronisation

Avec le modèle de jeton de synchronisation, seule la page la plus récemment chargée contient un jeton anti-contrefaçon valide. L'utilisation de plusieurs onglets peut être problématique. Par exemple, si un utilisateur ouvre plusieurs onglets :

  • Seul l'onglet chargé le plus récemment contient un jeton anti-contrefaçon valide.
  • Les requêtes effectuées à partir d'onglets précédemment chargés échouent avec une erreur : Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Envisagez d'autres modèles de protection CSRF si cela pose un problème.

Configurer l'anti-contrefaçon avec AntiforgeryOptions

Personnaliser AntiforgeryOptions en Program.cs :

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

Définissez les propriétés Cookie anti-contrefaçon à l'aide des propriétés de la classe CookieBuilder, comme indiqué dans le tableau suivant.

Option Description
Cookie Détermine les paramètres utilisés pour créer les cookies anti-contrefaçons.
FormFieldName Le nom du champ de formulaire masqué utilisé par le système anti-contrefaçon pour rendre les jetons anti-contrefaçon dans les vues.
HeaderName Le nom de l'en-tête utilisé par le système anti-contrefaçon. Si null, le système ne prend en compte que les données du formulaire.
SuppressXFrameOptionsHeader Spécifie s'il faut supprimer la génération de X-Frame-Options en-tête. Par défaut, l'en-tête est généré avec une valeur de "SAMEORIGIN". La valeur par défaut est false.

Pour plus d’informations, voir CookieAuthenticationOptions.

Générez des jetons anti-contrefaçon avec IAntiforgery

IAntiforgery fournit l'API pour configurer les fonctionnalités anti-contrefaçon. IAntiforgery peut être demandé en Program.cs à l’aide de WebApplication.Services. L'exemple suivant utilise le middleware de la page d'accueil de l'application pour générer un jeton anti-contrefaçon et l'envoyer dans la réponse en tant que 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);
});

L'exemple précédent définit un cookie nommé XSRF-TOKEN. Le client peut le lire cookie et fournir sa valeur sous forme d'en-tête attaché aux requêtes AJAX. Par exemple, Angular inclut une protection XSRF intégrée qui lit un cookie nommé XSRF-TOKEN par défaut.

Exiger une validation anti-contrefaçon

Le filtre d'action ValidateAntiForgeryToken peut être appliqué à une action individuelle, à un contrôleur ou globalement. Les requêtes adressées aux actions auxquelles ce filtre est appliqué sont bloquées, sauf si la requête inclut un jeton anti-contrefaçon valide :

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

    return RedirectToAction();
}

L'attribut ValidateAntiForgeryToken requiert un jeton pour les requêtes aux méthodes d'action qu'il marque, y compris les requêtes HTTP GET. Si l'attribut ValidateAntiForgeryToken est appliqué sur les contrôleurs de l'application, il peut être remplacé par l'attribut IgnoreAntiforgeryToken.

Valider automatiquement les jetons anti-contrefaçon pour les méthodes HTTP non sécurisées uniquement

Au lieu d'appliquer largement l'attribut ValidateAntiForgeryToken, puis de le remplacer par des attributs IgnoreAntiforgeryToken, l'attribut AutoValidateAntiforgeryToken peut être utilisé. Cet attribut fonctionne de la même manière que l'attribut ValidateAntiForgeryToken, sauf qu'il ne nécessite pas de jetons pour les requêtes effectuées à l'aide des méthodes HTTP suivantes :

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Nous vous recommandons d'utiliser AutoValidateAntiforgeryToken largement pour les scénarios non API. Cet attribut garantit que les actions POST sont protégées par défaut. L'alternative consiste à ignorer les jetons anti-contrefaçon par défaut, sauf si ValidateAntiForgeryToken cela s'applique à des méthodes d'action individuelles. Dans ce scénario, il est plus probable qu'une méthode d'action POST ne soit pas protégée par erreur, laissant l'application vulnérable aux attaques CSRF. Tous les POST doivent envoyer le jeton anti-contrefaçon.

Les API n'ont pas de mécanisme automatique pour envoyer la non-cookie partie du jeton. L'implémentation dépend probablement de l'implémentation du code client. Quelques exemples sont présentés ci-dessous :

Exemple au niveau de la classe :

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Exemple global :

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

Remplacer les attributs anti-contrefaçon globaux ou du contrôleur

Le filtre IgnoreAntiforgeryToken est utilisé pour éliminer le besoin d'un jeton anti-contrefaçon pour une action (ou contrôleur) donnée. Lorsqu'il est appliqué, ce filtre remplace ValidateAntiForgeryToken et AutoValidateAntiforgeryToken filtre les spécifications à un niveau supérieur (globalement ou sur un contrôleur).

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

    return RedirectToAction();
}

Actualiser les jetons après l'authentification

Les jetons doivent être actualisés une fois l'utilisateur authentifié en le redirigeant vers une vue ou une page Pages Razor.

JavaScript, AJAX et SPA

Dans les applications HTML traditionnelles, les jetons anti-contrefaçon sont transmis au serveur à l'aide de champs de formulaire masqués. Dans les applications et les SPA modernes basés sur JavaScript, de nombreuses demandes sont effectuées par programmation. Ces requêtes AJAX peuvent utiliser d'autres techniques (telles que des en-têtes de requête ou des cookies) pour envoyer le jeton.

Si les cookies sont utilisés pour stocker des jetons d'authentification et pour authentifier les demandes d'API sur le serveur, CSRF est un problème potentiel. Si le stockage local est utilisé pour stocker le jeton, la vulnérabilité CSRF peut être atténuée car les valeurs du stockage local ne sont pas envoyées automatiquement au serveur à chaque requête. L'utilisation du stockage local pour stocker le jeton anti-contrefaçon sur le client et l'envoi du jeton en tant qu'en-tête de requête est une approche recommandée.

JavaScript

En utilisant JavaScript avec des vues, le jeton peut être créé à l'aide d'un service à partir de la vue. Injectez le service IAntiforgery dans la vue et appelez 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>
}

L'exemple précédent utilise JavaScript pour lire la valeur du champ masqué pour l'en-tête AJAX POST.

Cette approche élimine le besoin de traiter directement les paramètres cookies du serveur ou de les lire depuis le client. Cependant, lorsque l'injection du service IAntiforgery n'est pas possible, JavaScript peut également accéder au jeton dans cookies, obtenu à partir d'une requête supplémentaire au serveur (généralement same-origin), et utiliser le contenu de cookies pour créer un en-tête avec la valeur du jeton.

En supposant que le script envoie le jeton dans un en-tête de requête appelé X-XSRF-TOKEN, configurez le service anti-contrefaçon pour rechercher X-XSRF-TOKEN en-tête :

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

L'exemple suivant ajoute un point de terminaison protégé qui écrira le jeton de requête dans un JavaScript lisible cookie :

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

L'exemple suivant utilise JavaScript pour effectuer une requête AJAX afin d'obtenir le jeton et effectuer une autre requête avec l'en-tête approprié :

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

Authentification Windows et anti-contrefaçon cookies

Lors de l'utilisation de l'authentification Windows, les points de terminaison d'application doivent être protégés contre les attaques CSRF de la même manière que pour cookies. Le navigateur envoie implicitement le contexte d'authentification au serveur et les terminaux doivent donc être protégés contre les attaques CSRF.

Étendre l'anti-contrefaçon

Le type IAntiforgeryAdditionalDataProvider permet aux développeurs d'étendre le comportement du système anti-CSRF en effectuant des allers-retours de données supplémentaires dans chaque jeton. La méthode GetAdditionalData est appelée chaque fois qu'un jeton de champ est généré et la valeur de retour est intégrée dans le jeton généré. Un implémenteur peut renvoyer un horodatage, un nonce ou toute autre valeur, puis appeler ValidateAdditionalData pour valider ces données lorsque le jeton est validé. Le nom d'utilisateur du client est déjà intégré dans les jetons générés, il n'est donc pas nécessaire d'inclure ces informations. Si un jeton inclut des données supplémentaires mais qu'aucune IAntiForgeryAdditionalDataProvider n'est configurée, les données supplémentaires ne sont pas validées.

Ressources supplémentaires

La falsification de requêtes intersites (également connue sous le nom de XSRF ou CSRF) est une attaque contre les applications hébergées sur le Web par laquelle une application Web malveillante peut influencer l'interaction entre un navigateur client et une application Web qui fait confiance à ce navigateur. Ces attaques sont possibles car les navigateurs Web envoient automatiquement certains types de jetons d'authentification à chaque requête adressée à un site Web. Cette forme d'exploit est également connue sous le nom d'attaque en un clic ou de chevauchement de session, car l'attaque tire parti de la session précédemment authentifiée de l'utilisateur.

Un exemple d'attaque CSRF :

  1. Un utilisateur se connecte www.good-banking-site.example.com à l'aide de l'authentification par formulaire. Le serveur authentifie l'utilisateur et émet une réponse qui inclut une authentification cookie. Le site est vulnérable aux attaques car il fait confiance à toute requête qu'il reçoit avec une authentification valide cookie.

  2. L'utilisateur visite un site malveillant, www.bad-crook-site.example.com.

    Le site malveillant, www.bad-crook-site.example.com, contient un formulaire HTML similaire à l'exemple suivant :

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

    Notez que les publications du formulaire action sur le site vulnérable, pas sur le site malveillant. Il s'agit de la partie "intersites" de CSRF.

  3. L'utilisateur sélectionne le bouton Soumettre. Le navigateur fait la demande et inclut automatiquement l'authentification cookie pour le domaine demandé, www.good-banking-site.example.com.

  4. La requête s'exécute sur le serveur www.good-banking-site.example.com avec le contexte d'authentification de l'utilisateur et peut effectuer toute action qu'un utilisateur authentifié est autorisé à effectuer.

En plus du scénario où l'utilisateur sélectionne le bouton pour soumettre le formulaire, le site malveillant pourrait :

  • Exécutez un script qui soumet automatiquement le formulaire.
  • Envoyez la soumission du formulaire en tant que requête AJAX.
  • Masquez le formulaire à l'aide de CSS.

Ces scénarios alternatifs ne nécessitent aucune action ou entrée de la part de l'utilisateur autre que la visite initiale du site malveillant.

L'utilisation de HTTPS n'empêche pas une attaque CSRF. Le site malveillant peut envoyer une requête https://www.good-banking-site.com/ aussi facilement qu'il peut envoyer une requête non sécurisée.

Certaines attaques ciblent les endpoints qui répondent aux requêtes GET, auquel cas une balise d'image peut être utilisée pour effectuer l'action. Cette forme d'attaque est courante sur les sites de forum qui autorisent les images mais bloquent JavaScript. Les applications qui changent d'état sur les requêtes GET, où des variables ou des ressources sont modifiées, sont vulnérables aux attaques malveillantes. Les requêtes GET qui changent d'état ne sont pas sécurisées. Une bonne pratique consiste à ne jamais modifier l'état d'une requête GET.

Les attaques CSRF sont possibles contre les applications Web qui utilisent cookies pour l'authentification car :

  • Les navigateurs stockent les cookies émis par une application Web.
  • Les cookies stockés incluent les sessions cookies pour les utilisateurs authentifiés.
  • Les navigateurs envoient tous les cookies associés à un domaine à l'application Web à chaque requête, quelle que soit la manière dont la demande à l'application a été générée dans le navigateur.

Cependant, les attaques CSRF ne se limitent pas à exploiter cookies. Par exemple, l'authentification De base et Digest sont également vulnérables. Une fois qu'un utilisateur s'est connecté avec l'authentification De base ou Digest, le navigateur envoie automatiquement les informations d'identification jusqu'à la fin de la session.

Dans ce contexte, la session fait référence à la session côté client au cours de laquelle l'utilisateur est authentifié. Il n'est pas lié aux sessions côté serveur ou au middleware de session ASP.NET Core.

Les utilisateurs peuvent se prémunir contre les vulnérabilités CSRF en prenant des précautions :

  • Déconnectez-vous des applications Web lorsque vous avez fini de les utiliser.
  • Effacez périodiquement les navigateurs cookies.

Cependant, les vulnérabilités CSRF sont fondamentalement un problème avec l'application Web, pas avec l'utilisateur final.

Concepts de base de l’authentification

Cookie-authentification basée sur est une forme d'authentification populaire. Les systèmes d'authentification basés sur des jetons gagnent en popularité, en particulier pour les applications à page unique (SPA).

Lorsqu'un utilisateur s'authentifie à l'aide de son nom d'utilisateur et de son mot de passe, il reçoit un jeton contenant un ticket d'authentification pouvant être utilisé pour l'authentification et l'autorisation. Le jeton est stocké sous la forme d'un cookie qui est envoyé avec chaque requête faite par le client. La génération et la validation de cookie sont effectuées par le middleware d'authentification Cookie. Le middleware sérialise un principal d'utilisateur dans un fichier cookie. Lors des requêtes suivantes, le middleware valide le cookie, recrée le principal et attribue le principal à la propriété HttpContext.User.

Authentification basée sur un jeton

Lorsqu'un utilisateur est authentifié, il reçoit un jeton (et non un jeton anti-contrefaçon). Le jeton contient des informations sur l'utilisateur sous la forme de revendications ou d'un jeton de référence qui pointe l'application vers l'état de l'utilisateur maintenu dans l'application. Lorsqu'un utilisateur tente d'accéder à une ressource nécessitant une authentification, le jeton est envoyé à l'application avec un en-tête d'autorisation supplémentaire sous la forme d'un jeton Bearer. Cette approche rend l'application sans état. Dans chaque demande suivante, le jeton est transmis dans la requête de validation côté serveur. Ce token n'est pas chiffré; c'est encodé. Sur le serveur, le jeton est décodé pour accéder à ses informations. Pour envoyer le jeton lors de requêtes ultérieures, stockez le jeton dans le stockage local du navigateur. Ne vous inquiétez pas de la vulnérabilité CSRF si le jeton est stocké dans le stockage local du navigateur. CSRF est un problème lorsque le jeton est stocké dans un fichier cookie. Pour plus d'informations, consultez l'exemple de code SPA du problème GitHub ajoute deux cookies.

Plusieurs applications hébergées sur un domaine

Les environnements d'hébergement partagé sont vulnérables au piratage de session, à la connexion CSRF et à d'autres attaques.

Bien que example1.contoso.net et example2.contoso.net soient des hôtes différents, il existe une relation d'approbation implicite entre les hôtes du domaine *.contoso.net. Cette relation de confiance implicite permet à des hôtes potentiellement non approuvés d'affecter les cookies les uns des autres (les politiques de même origine qui régissent les requêtes AJAX ne s'appliquent pas nécessairement aux HTTP cookies).

Les attaques qui exploitent les cookies de confiance entre les applications hébergées sur le même domaine peuvent être évitées en ne partageant pas les domaines. Lorsque chaque application est hébergée sur son propre domaine, il n'y a pas de relation de confiance implicite cookie à exploiter.

Configuration anti-contrefaçon ASP.NET Core

Avertissement

ASP.NET Core implémente l'anti-contrefaçon à l'aide de ASP.NET Core Data Protection. La pile de protection des données doit être configurée pour fonctionner dans une batterie de serveurs. Pour plus d'informations, voir Configuration de la protection des données.

Le middleware anti-contrefaçon est ajouté au conteneur d'injection de dépendances lorsque l'une des API suivantes est appelée dans Startup.ConfigureServices :

Dans ASP.NET Core 2.0 ou version ultérieure, le FormTagHelper injecte des jetons anti-contrefaçon dans les éléments de formulaire HTML. Le balisage suivant dans un fichier Razor génère automatiquement des jetons anti-contrefaçon :

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

De même, IHtmlHelper.BeginForm génère des jetons anti-contrefaçon par défaut si la méthode du formulaire n'est pas GET.

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML se produit lorsque la balise <form> contient l'attribut method="post" et que l'une des conditions suivantes est vraie :

  • L'attribut action est vide (action="").
  • L'attribut action n'est pas fourni (<form method="post">).

La génération automatique de jetons anti-contrefaçon pour les éléments de formulaire HTML peut être désactivée :

  • Désactivez explicitement les jetons anti-contrefaçon avec l'attribut asp-antiforgery :

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • L'élément de formulaire est désactivé des Tag Helpers en utilisant le Tag Helper ! symbole d'exclusion :

    <!form method="post">
        ...
    </!form>
    
  • Supprimez le FormTagHelper de la vue. Le FormTagHelper peut être supprimé d'une vue en ajoutant la directive suivante à la vue Razor :

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

Note

Razor Pages sont automatiquement protégées contre XSRF/CSRF. Pour plus d'informations, voir XSRF/CSRF Razor et Pages.

L'approche la plus courante pour se défendre contre les attaques CSRF consiste à utiliser le Synchronizer Token Pattern (STP). STP est utilisé lorsque l'utilisateur demande une page avec des données de formulaire :

  1. Le serveur envoie un jeton associé à l'identité de l'utilisateur actuel au client.
  2. Le client renvoie le jeton au serveur pour vérification.
  3. Si le serveur reçoit un jeton qui ne correspond pas à l'identité de l'utilisateur authentifié, la requête est rejetée.

Le jeton est unique et imprévisible. Le jeton peut également être utilisé pour assurer le bon séquencement d'une série de requêtes (par exemple, assurer la séquence de requête de : page 1 > page 2 > page 3). Tous les formulaires des modèles ASP.NET Core MVC et Pages Razor génèrent des jetons anti-contrefaçon. La paire d'exemples de vue suivante génère des jetons anti-contrefaçon :

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

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

Ajoutez explicitement un jeton anti-contrefaçon à un élément <form> sans utiliser les Tag Helpers avec le helper HTML @Html.AntiForgeryToken :

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

Dans chacun des cas précédents, ASP.NET Core ajoute un champ de formulaire masqué similaire à l'exemple suivant :

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

ASP.NET Core inclut trois filtres pour travailler avec des jetons anti-contrefaçon :

Options anti-contrefaçon

Personnaliser AntiforgeryOptions en Startup.ConfigureServices :

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

Définissez les propriétés Cookie anti-contrefaçon à l'aide des propriétés de la classe CookieBuilder, comme indiqué dans le tableau suivant.

Option Description
Cookie Détermine les paramètres utilisés pour créer les cookies anti-contrefaçons.
FormFieldName Le nom du champ de formulaire masqué utilisé par le système anti-contrefaçon pour rendre les jetons anti-contrefaçon dans les vues.
HeaderName Le nom de l'en-tête utilisé par le système anti-contrefaçon. Si null, le système ne prend en compte que les données du formulaire.
SuppressXFrameOptionsHeader Spécifie s'il faut supprimer la génération de X-Frame-Options en-tête. Par défaut, l'en-tête est généré avec une valeur de "SAMEORIGIN". La valeur par défaut est false.

Pour plus d’informations, voir CookieAuthenticationOptions.

Configurer les fonctionnalités anti-contrefaçon avec IAntiforgery

IAntiforgery fournit l'API pour configurer les fonctionnalités anti-contrefaçon. IAntiforgery peut être demandé dans la méthode Configure de la classe Startup.

Dans l’exemple suivant :

  • Le middleware de la page d'accueil de l'application est utilisé pour générer un jeton anti-contrefaçon et l'envoyer dans la réponse en tant que fichier cookie.
  • Le jeton de requête est envoyé en tant que lisible par JavaScript cookie avec la convention de dénomination angulaire par défaut décrite dans la section AngulaireJS.
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);
    });
}

Exiger une validation anti-contrefaçon

ValidateAntiForgeryToken est un filtre d'action qui peut être appliqué à une action individuelle, à un contrôleur ou globalement. Les requêtes adressées aux actions auxquelles ce filtre est appliqué sont bloquées à moins que la demande n'inclue un jeton anti-contrefaçon valide.

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

L'attribut ValidateAntiForgeryToken requiert un jeton pour les requêtes aux méthodes d'action qu'il marque, y compris les requêtes HTTP GET. Si l'attribut ValidateAntiForgeryToken est appliqué sur les contrôleurs de l'application, il peut être remplacé par l'attribut IgnoreAntiforgeryToken.

Note

ASP.NET Core ne prend pas en charge l'ajout automatique de jetons anti-contrefaçon aux requêtes GET.

Valider automatiquement les jetons anti-contrefaçon pour les méthodes HTTP non sécurisées uniquement

Les applications ASP.NET Core ne génèrent pas de jetons anti-contrefaçon pour les méthodes HTTP sécurisées (GET, HEAD, OPTIONS et TRACE). Au lieu d'appliquer largement l'attribut ValidateAntiForgeryToken, puis de le remplacer par des attributs IgnoreAntiforgeryToken, l'attribut AutoValidateAntiforgeryToken peut être utilisé. Cet attribut fonctionne de la même manière que l'attribut ValidateAntiForgeryToken, sauf qu'il ne nécessite pas de jetons pour les requêtes effectuées à l'aide des méthodes HTTP suivantes :

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Nous vous recommandons d'utiliser AutoValidateAntiforgeryToken largement pour les scénarios non API. Cet attribut garantit que les actions POST sont protégées par défaut. L'alternative consiste à ignorer les jetons anti-contrefaçon par défaut, sauf si ValidateAntiForgeryToken cela s'applique à des méthodes d'action individuelles. Dans ce scénario, il est plus probable qu'une méthode d'action POST ne soit pas protégée par erreur, laissant l'application vulnérable aux attaques CSRF. Tous les POST doivent envoyer le jeton anti-contrefaçon.

Les API n'ont pas de mécanisme automatique pour envoyer la non-cookie partie du jeton. L'implémentation dépend probablement de l'implémentation du code client. Quelques exemples sont présentés ci-dessous :

Exemple au niveau de la classe :

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

Exemple global :

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

Remplacer les attributs anti-contrefaçon globaux ou du contrôleur

Le filtre IgnoreAntiforgeryToken est utilisé pour éliminer le besoin d'un jeton anti-contrefaçon pour une action (ou contrôleur) donnée. Lorsqu'il est appliqué, ce filtre remplace ValidateAntiForgeryToken et AutoValidateAntiforgeryToken filtre les spécifications à un niveau supérieur (globalement ou sur un contrôleur).

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

Actualiser les jetons après l'authentification

Les jetons doivent être actualisés une fois l'utilisateur authentifié en le redirigeant vers une vue ou une page Pages Razor.

JavaScript, AJAX et SPA

Dans les applications HTML traditionnelles, les jetons anti-contrefaçon sont transmis au serveur à l'aide de champs de formulaire masqués. Dans les applications et les SPA modernes basés sur JavaScript, de nombreuses demandes sont effectuées par programmation. Ces requêtes AJAX peuvent utiliser d'autres techniques (telles que des en-têtes de requête ou des cookies) pour envoyer le jeton.

Si les cookies sont utilisés pour stocker des jetons d'authentification et pour authentifier les demandes d'API sur le serveur, CSRF est un problème potentiel. Si le stockage local est utilisé pour stocker le jeton, la vulnérabilité CSRF peut être atténuée car les valeurs du stockage local ne sont pas envoyées automatiquement au serveur à chaque requête. L'utilisation du stockage local pour stocker le jeton anti-contrefaçon sur le client et l'envoi du jeton en tant qu'en-tête de requête est une approche recommandée.

JavaScript

En utilisant JavaScript avec des vues, le jeton peut être créé à l'aide d'un service à partir de la vue. Injectez le service IAntiforgery dans la vue et appelez 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>

Cette approche élimine le besoin de traiter directement les paramètres cookies du serveur ou de les lire depuis le client.

L'exemple précédent utilise JavaScript pour lire la valeur du champ masqué pour l'en-tête AJAX POST.

JavaScript peut également accéder aux jetons dans cookies et utiliser le contenu de cookies pour créer un en-tête avec la valeur du jeton.

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

En supposant que le script demande d'envoyer le jeton dans un en-tête appelé X-CSRF-TOKEN, configurez le service anti-contrefaçon pour rechercher X-CSRF-TOKEN en-tête :

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

L'exemple suivant utilise JavaScript pour effectuer une requête AJAX avec l'en-tête approprié :

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

AngulaireJS

AngularJS utilise une convention pour traiter CSRF. Si le serveur envoie un cookie avec le nom XSRF-TOKEN, le service AngularJS$http ajoute la valeur cookie à un en-tête lorsqu'il envoie une requête au serveur. Ce processus est automatique. Le client n'a pas besoin de définir explicitement l'en-tête. Le nom de l'en-tête est X-XSRF-TOKEN. Le serveur doit détecter cet en-tête et valider son contenu.

Pour que l'API ASP.NET Core fonctionne avec cette convention au démarrage de votre application :

  • Configurez votre application pour fournir un jeton dans un cookie appelé XSRF-TOKEN.
  • Configurez le service anti-contrefaçon pour rechercher un en-tête nommé X-XSRF-TOKEN, qui est le nom d'en-tête par défaut d'Angular pour l'envoi du jeton 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");
}

Note

Lorsque le jeton anti-contrefaçon est fourni dans l’en-tête de requête et dans la charge utile du formulaire, seul le jeton de l’en-tête est validé.

Authentification Windows et anti-contrefaçon cookies

Lors de l'utilisation de l'authentification Windows, les points de terminaison d'application doivent être protégés contre les attaques CSRF de la même manière que pour cookies. Le navigateur envoie implicitement le contexte d'authentification au serveur et les terminaux doivent donc être protégés contre les attaques CSRF.

Étendre l'anti-contrefaçon

Le type IAntiforgeryAdditionalDataProvider permet aux développeurs d'étendre le comportement du système anti-CSRF en effectuant des allers-retours de données supplémentaires dans chaque jeton. La méthode GetAdditionalData est appelée chaque fois qu'un jeton de champ est généré et la valeur de retour est intégrée dans le jeton généré. Un implémenteur peut renvoyer un horodatage, un nonce ou toute autre valeur, puis appeler ValidateAdditionalData pour valider ces données lorsque le jeton est validé. Le nom d'utilisateur du client est déjà intégré dans les jetons générés, il n'est donc pas nécessaire d'inclure ces informations. Si un jeton inclut des données supplémentaires mais qu'aucune IAntiForgeryAdditionalDataProvider n'est configurée, les données supplémentaires ne sont pas validées.

Ressources supplémentaires