Utiliser des cookies SameSite dans ASP.NET Core

Par Rick Anderson

SameSite est un projet de norme IETF conçu pour fournir une certaine protection contre les attaques de falsification de requête intersites (CSRF). Initialement rédigé en 2016, l’ébauche de norme a été mise à jour en 2019. La norme mise à jour n’est pas rétrocompatible avec la norme précédente, les différences les plus notables étant les suivantes :

  • Les cookies sans en-tête SameSite sont traités comme des SameSite=Lax par défaut.
  • SameSite=None doit être utilisé pour autoriser l’utilisation des cookies intersites.
  • Les cookies qui affirment SameSite=None doivent également être marqués comme Secure.
  • Les applications qui utilisent <iframe> peuvent rencontrer des problèmes avec les cookies sameSite=Lax ou sameSite=Strict, car <iframe> est traité comme des scénarios intersites.
  • La valeur SameSite=None n’est pas autorisée par la norme de 2016 et conduit certaines implémentations à traiter ces cookies comme SameSite=Strict. Consultez Prise en charge des navigateurs plus anciens dans ce document.

Le paramètre SameSite=Lax fonctionne pour la plupart des cookies d’application. Certaines formes d’authentification comme OpenID Connect (OIDC) et WS-Federation utilisent par défaut des redirections basées sur POST. Les redirections basées sur POST déclenchent les protections du navigateur SameSite, de sorte que SameSite est désactivé pour ces composants. La plupart des connexions OAuth ne sont pas affectées en raison de différences dans la façon dont les requêtes sont acheminées.

Chaque composant ASP.NET Core qui émet des cookies doit décider si SameSite est approprié.

SameSite et identité

L’identité ASP.NET Core n’est généralement pas affectée par les cookies SameSite, à l’exception de scénarios avancés tels que l’intégration IFrames ou OpenIdConnect.

Lorsque vous utilisez Identity, n’ajoutez aucun fournisseur de cookies et n’appelez pas services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme), Identity s’en charge.

Exemple de code de test SameSite

L’exemple suivant peut être téléchargé et testé :

Sample Document
Razor Pages ASP.NET Core exemple de cookie Razor Pages SameSite 3.1

Prise en charge de .NET pour l'attribut SameSite

.NET prend en charge le projet de norme 2019 pour SameSite. Les développeurs peuvent contrôler par programmation la valeur de l’attribut SameSite à l’aide de la propriété HttpCookie.SameSite. La définition de la propriété SameSite à Strict, Lax ou None entraîne l'écriture de ces valeurs sur le réseau avec le cookie. Le paramètre défini sur SameSiteMode.Unspecified indique qu’aucun SameSite ne doit être envoyé avec le cookie.

    var cookieOptions = new CookieOptions
    {
        // Set the secure flag, which Chrome's changes will require for SameSite none.
        // Note this will also require you to be running on HTTPS.
        Secure = true,

        // Set the cookie to HTTP only which is good practice unless you really do need
        // to access it client side in scripts.
        HttpOnly = true,

        // Add the SameSite attribute, this will emit the attribute with a value of none.
        SameSite = SameSiteMode.None

        // The client should follow its default cookie policy.
        // SameSite = SameSiteMode.Unspecified
    };

    // Add the cookie to the response cookie collection
    Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);
}

Utilisation de l’API avec SameSite

HttpContext.Response.Cookies.Append a pour valeur par défaut Unspecified, ce qui signifie qu’aucun attribut SameSite n’est ajouté au cookie et le client utilisera son comportement par défaut (Lax pour les nouveaux navigateurs, None pour les anciens navigateurs). Le code suivant montre comment modifier la valeur SameSite du cookie en SameSiteMode.Lax:

HttpContext.Response.Cookies.Append(
                     "name", "value",
                     new CookieOptions() { SameSite = SameSiteMode.Lax });

Tous les composants ASP.NET Core qui émettent des cookies remplacent les valeurs par défaut précédentes par des paramètres appropriés pour leurs scénarios. Les valeurs par défaut précédentes redéfinies n’ont pas changé.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Authentification par cookies CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

ASP.NET Core 3.1 ou version ultérieure prend en charge la fonctionnalité SameSite suivante :

  • Redéfinit le comportement de SameSiteMode.None à émettre SameSite=None
  • Ajoute une nouvelle valeur SameSiteMode.Unspecified pour omettre l’attribut SameSite.
  • Toutes les API de cookies utilisent par défaut Unspecified. Certains composants qui utilisent des cookies définissent des valeurs plus spécifiques à leurs scénarios. Consultez le tableau ci-dessus pour voir des exemples.

Dans ASP.NET Core 3.0 ou version ultérieure, les valeurs par défaut sameSite ont été modifiées pour éviter les conflits avec les valeurs par défaut du client incohérentes. Les API suivantes ont modifié la valeur par défaut de SameSiteMode.Lax à -1 pour éviter d’émettre un attribut SameSite pour ces cookies :

Historique et modifications

La prise en charge de SameSite a été implémentée pour la première fois dans ASP.NET Core dans la version 2.0 selon la norme provisoire de 2016. La norme 2016 était facultative. ASP.NET Core a activé cette option en définissant plusieurs cookies à Lax par défaut. Après avoir rencontré plusieurs problèmes d’authentification, la plupart des utilisations de SameSite ont été désactivées.

Des correctifs ont été publiés en novembre 2019 pour passer de la norme 2016 à la norme 2019. Le brouillon 2019 de la spécification SameSite :

  • N’est pas rétrocompatible avec le brouillon de 2016. Pour plus d’informations, consultez Prise en charge des navigateurs plus anciens dans ce document.
  • Spécifie que les cookies sont traités comme des SameSite=Lax par défaut.
  • Spécifie que les cookies qui indiquent explicitement SameSite=None afin d’autoriser la livraison intersites doivent être marqués en tant que Secure. None est une nouvelle entrée pour se désinscrire.
  • Est pris en charge par les correctifs émis pour ASP.NET Core 2.1, 2.2 et 3.0. ASP.NET Core 3.1 ou version ultérieure dispose d’une prise en charge supplémentaire de SameSite.
  • Est prévu pour être activé par Chrome par défaut en février 2020. Les navigateurs ont commencé à passer à cette norme en 2019.

API affectées par le passage de la norme brouillon SameSite 2016 à la norme brouillon SameSite 2019

Prise en charge des navigateurs plus anciens

La norme SameSite 2016 exigeait que les valeurs inconnues soient traitées comme des valeurs SameSite=Strict. Les applications accessibles à partir de navigateurs plus anciens qui prennent en charge la norme SameSite 2016 peuvent cesser de fonctionner lorsqu’elles obtiennent une propriété SameSite avec la valeur None. Les applications web doivent implémenter la détection de navigateur si elles ont l’intention de prendre en charge les navigateurs plus anciens. ASP.NET Core n’implémente pas la détection de navigateur, car les valeurs User-Agents sont très volatiles et changent fréquemment. Un point d’extension dans Microsoft.AspNetCore.CookiePolicy permet d’intégrer une logique spécifique au User-Agent.

Dans Program.cs, ajoutez du code qui appelle UseCookiePolicy avant d’appeler UseAuthentication ou toute méthode qui écrit des cookies :

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
    options.OnAppendCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    options.OnDeleteCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});

void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = SameSiteMode.Unspecified;
        }
    }
}

    builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseCookiePolicy();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Dans Program.cs, ajoutez du code similaire au code mis en surbrillance suivant :

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
    options.OnAppendCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    options.OnDeleteCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});

void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = SameSiteMode.Unspecified;
        }
    }
}

    builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseCookiePolicy();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Dans l’exemple précédent, MyUserAgentDetectionLib.DisallowsSameSiteNone est une bibliothèque fournie par l’utilisateur qui détecte si l’agent utilisateur ne prend pas en charge SameSite None :

if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
    options.SameSite = SameSiteMode.Unspecified;
}

Le code suivant montre un exemple de méthode DisallowsSameSiteNone :

Warning

Le code suivant est destiné à la démonstration uniquement :

  • Il ne doit pas être considéré comme complet.
  • Il n’est ni maintenu ni pris en charge.
public static bool DisallowsSameSiteNone(string userAgent)
{
    // Check if a null or empty string has been passed in, since this
    // will cause further interrogation of the useragent to fail.
     if (String.IsNullOrWhiteSpace(userAgent))
        return false;
    
    // Cover all iOS based browsers here. This includes:
    // - Safari on iOS 12 for iPhone, iPod Touch, iPad
    // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
    // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
    // All of which are broken by SameSite=None, because they use the iOS networking
    // stack.
    if (userAgent.Contains("CPU iPhone OS 12") ||
        userAgent.Contains("iPad; CPU OS 12"))
    {
        return true;
    }

    // Cover Mac OS X based browsers that use the Mac OS networking stack. 
    // This includes:
    // - Safari on Mac OS X.
    // This does not include:
    // - Chrome on Mac OS X
    // Because they do not use the Mac OS networking stack.
    if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
        userAgent.Contains("Version/") && userAgent.Contains("Safari"))
    {
        return true;
    }

    // Cover Chrome 50-69, because some versions are broken by SameSite=None, 
    // and none in this range require it.
    // Note: this covers some pre-Chromium Edge versions, 
    // but pre-Chromium Edge does not require SameSite=None.
    if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
    {
        return true;
    }

    return false;
}

Tester les applications pour les problèmes SameSite

Les applications qui interagissent avec des sites distants, par le biais d’une connexion tierce, par exemple, doivent :

Testez des applications web à l’aide d’une version cliente permettant d’activer le nouveau comportement SameSite. Chrome, Firefox et Chromium Edge ont tous de nouveaux indicateurs de fonctionnalité d’acceptation qui peuvent être utilisés pour les tests. Après avoir appliqué les correctifs SameSite à votre application, testez-la avec des versions clientes plus anciennes, en particulier Safari. Pour plus d’informations, consultez Prise en charge des navigateurs plus anciens dans ce document.

Tester avec Chrome

Chrome 78+ donne des résultats erronés, car une atténuation temporaire est en place. L’atténuation temporaire de Chrome 78+ autorise les cookies âgés de moins de deux minutes. Chrome 76 ou 77 avec les indicateurs de test appropriés activés fournit des résultats plus précis. Pour tester le bouton bascule du nouveau comportement SameSite, réglez chrome://flags/#same-site-by-default-cookies sur Activé. Les versions antérieures de Chrome (75 et versions antérieures) sont signalées comme échouant avec le nouveau paramètre None. Consultez Prise en charge des navigateurs plus anciens dans ce document.

Google ne met pas à disposition d’anciennes versions de Chrome. Suivez les instructions fournies dans Télécharger Chromium pour tester les anciennes versions de Chrome. Ne téléchargez pas Chrome à partir des liens fournis en recherchant des versions antérieures de Chrome.

À compter de la version Canary 80.0.3975.0, l’atténuation temporaire Lax+POST peut être désactivée à des fins de test à l’aide du nouvel indicateur --enable-features=SameSiteDefaultChecksMethodRigorously pour permettre le test des sites et des services dans l’état final de la fonctionnalité où l’atténuation a été supprimée. Pour plus d’informations, consultez les SameSite Updates de The Chromium Projects

Tester avec Safari

Safari 12 a strictement implémenté le brouillon précédent et échoue lorsque la nouvelle None valeur se trouve dans un cookie. None est évité(e) via le code de détection du navigateur Prise en charge des navigateurs plus anciens dans ce document. Testez Safari 12, Safari 13, ainsi que les connexions de type système d’exploitation basées sur WebKit à l’aide de Microsoft Authentication Library (MSAL), d’Active Directory Authentication Library (ADAL) ou de toute autre bibliothèque que vous utilisez. Le problème dépend de la version sous-jacente du système d’exploitation. OSX Mojave (10.14) et iOS 12 sont connus pour avoir des problèmes de compatibilité avec le nouveau comportement SameSite. La mise à niveau du système d’exploitation vers OSX Catalina (10.15) ou iOS 13 résout le problème. Safari ne dispose pas actuellement d’un drapeau d’activation pour tester le comportement défini par la nouvelle spécification.

Tester avec Firefox

La prise en charge de Firefox pour la nouvelle norme peut être testée sur la version 68+ en acceptant sur la page about:config avec l’indicateur de fonctionnalité network.cookie.sameSite.laxByDefault. Il n’y a pas eu de rapports de problèmes de compatibilité avec les versions antérieures de Firefox.

Tester avec le navigateur Edge

Edge prend en charge l’ancienne norme SameSite. Edge version 44 n’a pas de problèmes de compatibilité connus avec la nouvelle norme.

Tester avec Edge (Chromium)

Les indicateurs SameSite sont définis sur la edge://flags/#same-site-by-default-cookies page. Aucun problème de compatibilité n’a été détecté avec Edge Chromium.

Tester avec Electron

Les versions d’Electron incluent des versions antérieures de Chromium. Par exemple, la version d’Electron utilisée par Teams est Chromium 66, qui présente l’ancien comportement. Vous devez effectuer vos propres tests de compatibilité avec la version d’Electron utilisée par votre produit. Consultez Prise en charge des navigateurs plus anciens dans la section suivante.

Ressources supplémentaires

Sample Document
Razor Pages ASP.NET Core exemple de cookie Razor Pages SameSite 3.1

L’exemple suivant peut être téléchargé et testé :

Sample Document
Razor Pages ASP.NET Core exemple de cookie Razor Pages SameSite 3.1

Prise en charge de .NET Core pour l’attribut SameSite

.NET Core version 3.1 ou ultérieure prend en charge la version préliminaire de 2019 de la norme pour SameSite. Les développeurs peuvent contrôler par programmation la valeur de l’attribut SameSite à l’aide de la propriété HttpCookie.SameSite. La définition de la SameSite propriété sur Strict, Lax ou None entraîne l’écriture de ces valeurs sur le réseau avec le cookie. Le définir comme équivalent à (SameSiteMode)(-1) indique qu’aucun attribut SameSite ne doit être inclus sur le réseau avec le cookie

var cookieOptions = new CookieOptions
{
    // Set the secure flag, which Chrome's changes will require for SameSite none.
    // Note this will also require you to be running on HTTPS.
    Secure = true,

    // Set the cookie to HTTP only which is good practice unless you really do need
    // to access it client side in scripts.
    HttpOnly = true,

    // Add the SameSite attribute, this will emit the attribute with a value of none.
    // To not emit the attribute at all set
    // SameSite = (SameSiteMode)(-1)
    SameSite = SameSiteMode.None
};

// Add the cookie to the response cookie collection
Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);

.NET Core 3.1 ou version ultérieure prennent en charge les valeurs SameSite mises à jour et ajoutent une valeur SameSiteMode.Unspecified d’énumération supplémentaire à l’énumération SameSiteMode . Cette nouvelle valeur indique qu’aucun attribut SameSite ne doit être envoyé avec le cookie.

Utilisation de l’API avec SameSite

HttpContext.Response.Cookies.Append a pour valeur par défaut Unspecified, ce qui signifie qu’aucun attribut SameSite n’est ajouté au cookie et le client utilisera son comportement par défaut (Lax pour les nouveaux navigateurs, None pour les anciens navigateurs). Le code suivant montre comment modifier la valeur SameSite du cookie en SameSiteMode.Lax:

HttpContext.Response.Cookies.Append(
                     "name", "value",
                     new CookieOptions() { SameSite = SameSiteMode.Lax });

Tous les composants ASP.NET Core qui émettent des cookies remplacent les valeurs par défaut précédentes par des paramètres appropriés pour leurs scénarios. Les valeurs par défaut précédentes redéfinies n’ont pas changé.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Authentification par cookies CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

ASP.NET Core 3.1 ou version ultérieure prend en charge la fonctionnalité SameSite suivante :

  • Redéfinit le comportement de SameSiteMode.None à émettre SameSite=None
  • Ajoute une nouvelle valeur SameSiteMode.Unspecified pour omettre l’attribut SameSite.
  • Toutes les API de cookies utilisent par défaut Unspecified. Certains composants qui utilisent des cookies définissent des valeurs plus spécifiques à leurs scénarios. Consultez le tableau ci-dessus pour voir des exemples.

Dans ASP.NET Core 3.0 ou version ultérieure, les valeurs par défaut sameSite ont été modifiées pour éviter les conflits avec les valeurs par défaut du client incohérentes. Les API suivantes ont modifié la valeur par défaut de SameSiteMode.Lax à -1 pour éviter d’émettre un attribut SameSite pour ces cookies :

Historique et modifications

La prise en charge de SameSite a été implémentée pour la première fois dans ASP.NET Core dans la version 2.0 selon la norme provisoire de 2016. La norme 2016 était facultative. ASP.NET Core a activé cette option en définissant plusieurs cookies à Lax par défaut. Après avoir rencontré plusieurs problèmes d’authentification, la plupart des utilisations de SameSite ont été désactivées.

Des correctifs ont été publiés en novembre 2019 pour passer de la norme 2016 à la norme 2019. Le brouillon 2019 de la spécification SameSite :

  • N’est pas rétrocompatible avec le brouillon de 2016. Pour plus d’informations, consultez Prise en charge des navigateurs plus anciens dans ce document.
  • Spécifie que les cookies sont traités comme des SameSite=Lax par défaut.
  • Spécifie que les cookies qui indiquent explicitement SameSite=None afin d’autoriser la livraison intersites doivent être marqués en tant que Secure. None est une nouvelle entrée pour se désinscrire.
  • Est pris en charge par les correctifs émis pour ASP.NET Core 2.1, 2.2 et 3.0. ASP.NET Core 3.1 offre une prise en charge supplémentaire de SameSite.
  • Est prévu pour être activé par Chrome par défaut en février 2020. Les navigateurs ont commencé à passer à cette norme en 2019.

API affectées par le passage de la norme brouillon SameSite 2016 à la norme brouillon SameSite 2019

Prise en charge des navigateurs plus anciens

La norme SameSite 2016 exigeait que les valeurs inconnues soient traitées comme des valeurs SameSite=Strict. Les applications accessibles à partir de navigateurs plus anciens qui prennent en charge la norme SameSite 2016 peuvent cesser de fonctionner lorsqu’elles obtiennent une propriété SameSite avec la valeur None. Les applications web doivent implémenter la détection de navigateur si elles ont l’intention de prendre en charge les navigateurs plus anciens. ASP.NET Core n’implémente pas la détection de navigateur, car les valeurs User-Agents sont très volatiles et changent fréquemment. Un point d’extension dans Microsoft.AspNetCore.CookiePolicy permet d’intégrer une logique spécifique au User-Agent.

Dans Startup.Configure, ajoutez du code qui appelle UseCookiePolicy avant d’appeler UseAuthentication ou toute méthode qui écrit des cookies :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Dans Startup.ConfigureServices, ajoutez du code similaire à ce qui suit :

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
        options.OnAppendCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
        options.OnDeleteCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    });

    services.AddRazorPages();
}

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = SameSiteMode.Unspecified;
        }
    }
}

Dans l’exemple précédent, MyUserAgentDetectionLib.DisallowsSameSiteNone est une bibliothèque fournie par l’utilisateur qui détecte si l’agent utilisateur ne prend pas en charge SameSite None :

if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
    options.SameSite = SameSiteMode.Unspecified;
}

Le code suivant montre un exemple de méthode DisallowsSameSiteNone :

Warning

Le code suivant est destiné à la démonstration uniquement :

  • Il ne doit pas être considéré comme complet.
  • Il n’est ni maintenu ni pris en charge.
public static bool DisallowsSameSiteNone(string userAgent)
{
    // Check if a null or empty string has been passed in, since this
    // will cause further interrogation of the useragent to fail.
     if (String.IsNullOrWhiteSpace(userAgent))
        return false;
    
    // Cover all iOS based browsers here. This includes:
    // - Safari on iOS 12 for iPhone, iPod Touch, iPad
    // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
    // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
    // All of which are broken by SameSite=None, because they use the iOS networking
    // stack.
    if (userAgent.Contains("CPU iPhone OS 12") ||
        userAgent.Contains("iPad; CPU OS 12"))
    {
        return true;
    }

    // Cover Mac OS X based browsers that use the Mac OS networking stack. 
    // This includes:
    // - Safari on Mac OS X.
    // This does not include:
    // - Chrome on Mac OS X
    // Because they do not use the Mac OS networking stack.
    if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
        userAgent.Contains("Version/") && userAgent.Contains("Safari"))
    {
        return true;
    }

    // Cover Chrome 50-69, because some versions are broken by SameSite=None, 
    // and none in this range require it.
    // Note: this covers some pre-Chromium Edge versions, 
    // but pre-Chromium Edge does not require SameSite=None.
    if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
    {
        return true;
    }

    return false;
}

Tester les applications pour les problèmes SameSite

Les applications qui interagissent avec des sites distants, par le biais d’une connexion tierce, par exemple, doivent :

Testez des applications web à l’aide d’une version cliente permettant d’activer le nouveau comportement SameSite. Chrome, Firefox et Chromium Edge ont tous de nouveaux indicateurs de fonctionnalité d’acceptation qui peuvent être utilisés pour les tests. Après avoir appliqué les correctifs SameSite à votre application, testez-la avec des versions clientes plus anciennes, en particulier Safari. Pour plus d’informations, consultez Prise en charge des navigateurs plus anciens dans ce document.

Tester avec Chrome

Chrome 78+ donne des résultats erronés, car une atténuation temporaire est en place. L’atténuation temporaire de Chrome 78+ autorise les cookies âgés de moins de deux minutes. Chrome 76 ou 77 avec les indicateurs de test appropriés activés fournit des résultats plus précis. Pour tester le bouton bascule du nouveau comportement SameSite, réglez chrome://flags/#same-site-by-default-cookies sur Activé. Les versions antérieures de Chrome (75 et versions antérieures) sont signalées comme échouant avec le nouveau paramètre None. Consultez Prise en charge des navigateurs plus anciens dans ce document.

Google ne met pas à disposition d’anciennes versions de Chrome. Suivez les instructions fournies dans Télécharger Chromium pour tester les anciennes versions de Chrome. Ne téléchargez pas Chrome à partir des liens fournis en recherchant des versions antérieures de Chrome.

À compter de la version Canary 80.0.3975.0, l’atténuation temporaire Lax+POST peut être désactivée à des fins de test à l’aide du nouvel indicateur --enable-features=SameSiteDefaultChecksMethodRigorously pour permettre le test des sites et des services dans l’état final de la fonctionnalité où l’atténuation a été supprimée. Pour plus d’informations, consultez les SameSite Updates de The Chromium Projects

Tester avec Safari

Safari 12 a strictement implémenté le brouillon précédent et échoue lorsque la nouvelle None valeur se trouve dans un cookie. None est évité(e) via le code de détection du navigateur Prise en charge des navigateurs plus anciens dans ce document. Testez Safari 12, Safari 13, ainsi que les connexions de type système d’exploitation basées sur WebKit à l’aide de Microsoft Authentication Library (MSAL), d’Active Directory Authentication Library (ADAL) ou de toute autre bibliothèque que vous utilisez. Le problème dépend de la version sous-jacente du système d’exploitation. OSX Mojave (10.14) et iOS 12 sont connus pour avoir des problèmes de compatibilité avec le nouveau comportement SameSite. La mise à niveau du système d’exploitation vers OSX Catalina (10.15) ou iOS 13 résout le problème. Safari ne dispose pas actuellement d’un drapeau d’activation pour tester le comportement défini par la nouvelle spécification.

Tester avec Firefox

La prise en charge de Firefox pour la nouvelle norme peut être testée sur la version 68+ en acceptant sur la page about:config avec l’indicateur de fonctionnalité network.cookie.sameSite.laxByDefault. Il n’y a pas eu de rapports de problèmes de compatibilité avec les versions antérieures de Firefox.

Tester avec le navigateur Edge

Edge prend en charge l’ancienne norme SameSite. Edge version 44 n’a pas de problèmes de compatibilité connus avec la nouvelle norme.

Tester avec Edge (Chromium)

Les indicateurs SameSite sont définis sur la edge://flags/#same-site-by-default-cookies page. Aucun problème de compatibilité n’a été détecté avec Edge Chromium.

Tester avec Electron

Les versions d’Electron incluent des versions antérieures de Chromium. Par exemple, la version d’Electron utilisée par Teams est Chromium 66, qui présente l’ancien comportement. Vous devez effectuer vos propres tests de compatibilité avec la version d’Electron utilisée par votre produit. Consultez Prise en charge des navigateurs plus anciens dans la section suivante.

Ressources supplémentaires

Sample Document
Razor Pages ASP.NET Core exemple de cookie Razor Pages SameSite 3.1

Les exemples suivants peuvent être téléchargés et testés :

Sample Document
MVC exemple de cookie SameSite ASP.NET Core 2.1 MVC
Razor Pages exemple de cookie Razor Pages SameSite ASP.NET Core 2.1

Changements de comportement des correctifs de décembre

Le changement de comportement spécifique pour .NET Framework et .NET Core 2.1 est la façon dont la propriété SameSite interprète la valeur None. Avant le correctif, une valeur de None signifiait « Ne pas émettre l’attribut du tout », après le correctif, elle signifie « Émettre l’attribut avec une valeur de None». Après le correctif, une valeur SameSite de (SameSiteMode)(-1) empêche l’émission de l’attribut.

La valeur SameSite par défaut pour l’authentification par formulaire et les cookies d’état de session est passée de None à Lax.

Utilisation de l’API avec SameSite

HttpContext.Response.Cookies.Append a pour valeur par défaut Unspecified, ce qui signifie qu’aucun attribut SameSite n’est ajouté au cookie et le client utilisera son comportement par défaut (Lax pour les nouveaux navigateurs, None pour les anciens navigateurs). Le code suivant montre comment modifier la valeur SameSite du cookie en SameSiteMode.Lax:

HttpContext.Response.Cookies.Append(
                     "name", "value",
                     new CookieOptions() { SameSite = SameSiteMode.Lax });

Tous les composants ASP.NET Core qui émettent des cookies remplacent les valeurs par défaut précédentes par des paramètres appropriés pour leurs scénarios. Les valeurs par défaut précédentes redéfinies n’ont pas changé.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Authentification par cookies CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

Historique et modifications

La prise en charge de SameSite a été implémentée pour la première fois dans ASP.NET Core dans la version 2.0 selon la norme provisoire de 2016. La norme 2016 était facultative. ASP.NET Core a activé cette option en définissant plusieurs cookies à Lax par défaut. Après avoir rencontré plusieurs problèmes d’authentification, la plupart des utilisations de SameSite ont été désactivées.

Des correctifs ont été publiés en novembre 2019 pour passer de la norme 2016 à la norme 2019. Le brouillon 2019 de la spécification SameSite :

  • N’est pas rétrocompatible avec le brouillon de 2016. Pour plus d’informations, consultez Prise en charge des navigateurs plus anciens dans ce document.
  • Spécifie que les cookies sont traités comme des SameSite=Lax par défaut.
  • Spécifie que les cookies qui indiquent explicitement SameSite=None afin d’autoriser la livraison intersites doivent être marqués en tant que Secure. None est une nouvelle entrée pour se désinscrire.
  • Est pris en charge par les correctifs émis pour ASP.NET Core 2.1, 2.2 et 3.0. ASP.NET Core 3.1 offre une prise en charge supplémentaire de SameSite.
  • Est prévu pour être activé par Chrome par défaut en février 2020. Les navigateurs ont commencé à passer à cette norme en 2019.

API affectées par le passage de la norme brouillon SameSite 2016 à la norme brouillon SameSite 2019

Prise en charge des navigateurs plus anciens

La norme SameSite 2016 exigeait que les valeurs inconnues soient traitées comme des valeurs SameSite=Strict. Les applications accessibles à partir de navigateurs plus anciens qui prennent en charge la norme SameSite 2016 peuvent cesser de fonctionner lorsqu’elles obtiennent une propriété SameSite avec la valeur None. Les applications web doivent implémenter la détection de navigateur si elles ont l’intention de prendre en charge les navigateurs plus anciens. ASP.NET Core n’implémente pas la détection de navigateur, car les valeurs User-Agents sont très volatiles et changent fréquemment. Un point d’extension dans Microsoft.AspNetCore.CookiePolicy permet d’intégrer une logique spécifique au User-Agent.

Dans Startup.Configure, ajoutez du code qui appelle UseCookiePolicy avant d’appeler UseAuthentication ou toute méthode qui écrit des cookies :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Dans Startup.ConfigureServices, ajoutez du code similaire à ce qui suit :

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.MinimumSameSitePolicy = (SameSiteMode)(-1);
        options.OnAppendCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
        options.OnDeleteCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    });

    services.AddRazorPages();
}

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = (SameSiteMode)(-1);
        }

    }
}

Dans l’exemple précédent, MyUserAgentDetectionLib.DisallowsSameSiteNone est une bibliothèque fournie par l’utilisateur qui détecte si l’agent utilisateur ne prend pas en charge SameSite None :

if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent))
{
    options.SameSite = SameSiteMode.Unspecified;
}

Le code suivant montre un exemple de méthode DisallowsSameSiteNone :

Warning

Le code suivant est destiné à la démonstration uniquement :

  • Il ne doit pas être considéré comme complet.
  • Il n’est ni maintenu ni pris en charge.
public static bool DisallowsSameSiteNone(string userAgent)
{
    // Check if a null or empty string has been passed in, since this
    // will cause further interrogation of the useragent to fail.
     if (String.IsNullOrWhiteSpace(userAgent))
        return false;
    
    // Cover all iOS based browsers here. This includes:
    // - Safari on iOS 12 for iPhone, iPod Touch, iPad
    // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
    // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
    // All of which are broken by SameSite=None, because they use the iOS networking
    // stack.
    if (userAgent.Contains("CPU iPhone OS 12") ||
        userAgent.Contains("iPad; CPU OS 12"))
    {
        return true;
    }

    // Cover Mac OS X based browsers that use the Mac OS networking stack. 
    // This includes:
    // - Safari on Mac OS X.
    // This does not include:
    // - Chrome on Mac OS X
    // Because they do not use the Mac OS networking stack.
    if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
        userAgent.Contains("Version/") && userAgent.Contains("Safari"))
    {
        return true;
    }

    // Cover Chrome 50-69, because some versions are broken by SameSite=None, 
    // and none in this range require it.
    // Note: this covers some pre-Chromium Edge versions, 
    // but pre-Chromium Edge does not require SameSite=None.
    if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
    {
        return true;
    }

    return false;
}

Tester les applications pour les problèmes SameSite

Les applications qui interagissent avec des sites distants, par le biais d’une connexion tierce, par exemple, doivent :

Testez des applications web à l’aide d’une version cliente permettant d’activer le nouveau comportement SameSite. Chrome, Firefox et Chromium Edge ont tous de nouveaux indicateurs de fonctionnalité d’acceptation qui peuvent être utilisés pour les tests. Après avoir appliqué les correctifs SameSite à votre application, testez-la avec des versions clientes plus anciennes, en particulier Safari. Pour plus d’informations, consultez Prise en charge des navigateurs plus anciens dans ce document.

Tester avec Chrome

Chrome 78+ donne des résultats erronés, car une atténuation temporaire est en place. L’atténuation temporaire de Chrome 78+ autorise les cookies âgés de moins de deux minutes. Chrome 76 ou 77 avec les indicateurs de test appropriés activés fournit des résultats plus précis. Pour tester le bouton bascule du nouveau comportement SameSite, réglez chrome://flags/#same-site-by-default-cookies sur Activé. Les versions antérieures de Chrome (75 et versions antérieures) sont signalées comme échouant avec le nouveau paramètre None. Consultez Prise en charge des navigateurs plus anciens dans ce document.

Google ne met pas à disposition d’anciennes versions de Chrome. Suivez les instructions fournies dans Télécharger Chromium pour tester les anciennes versions de Chrome. Ne téléchargez pas Chrome à partir des liens fournis en recherchant des versions antérieures de Chrome.

À compter de la version Canary 80.0.3975.0, l’atténuation temporaire Lax+POST peut être désactivée à des fins de test à l’aide du nouvel indicateur --enable-features=SameSiteDefaultChecksMethodRigorously pour permettre le test des sites et des services dans l’état final de la fonctionnalité où l’atténuation a été supprimée. Pour plus d’informations, consultez les SameSite Updates de The Chromium Projects

Tester avec Safari

Safari 12 a strictement implémenté le brouillon précédent et échoue lorsque la nouvelle None valeur se trouve dans un cookie. None est évité(e) via le code de détection du navigateur Prise en charge des navigateurs plus anciens dans ce document. Testez Safari 12, Safari 13, ainsi que les connexions de type système d’exploitation basées sur WebKit à l’aide de Microsoft Authentication Library (MSAL), d’Active Directory Authentication Library (ADAL) ou de toute autre bibliothèque que vous utilisez. Le problème dépend de la version sous-jacente du système d’exploitation. OSX Mojave (10.14) et iOS 12 sont connus pour avoir des problèmes de compatibilité avec le nouveau comportement SameSite. La mise à niveau du système d’exploitation vers OSX Catalina (10.15) ou iOS 13 résout le problème. Safari ne dispose pas actuellement d’un drapeau d’activation pour tester le comportement défini par la nouvelle spécification.

Tester avec Firefox

La prise en charge de Firefox pour la nouvelle norme peut être testée sur la version 68+ en acceptant sur la page about:config avec l’indicateur de fonctionnalité network.cookie.sameSite.laxByDefault. Il n’y a pas eu de rapports de problèmes de compatibilité avec les versions antérieures de Firefox.

Tester avec le navigateur Edge

Edge prend en charge l’ancienne norme SameSite. Edge version 44 n’a pas de problèmes de compatibilité connus avec la nouvelle norme.

Tester avec Edge (Chromium)

Les indicateurs SameSite sont définis sur la edge://flags/#same-site-by-default-cookies page. Aucun problème de compatibilité n’a été détecté avec Edge Chromium.

Tester avec Electron

Les versions d’Electron incluent des versions antérieures de Chromium. Par exemple, la version d’Electron utilisée par Teams est Chromium 66, qui présente l’ancien comportement. Vous devez effectuer vos propres tests de compatibilité avec la version d’Electron utilisée par votre produit. Consultez Prise en charge des navigateurs plus anciens dans la section suivante.

Ressources supplémentaires

Sample Document
MVC exemple de cookie SameSite ASP.NET Core 2.1 MVC
Razor Pages exemple de cookie Razor Pages SameSite ASP.NET Core 2.1