Partager via


Utiliser des cookies SameSite dans ASP.NET Core

Par Rick Anderson

SameSite est un brouillon 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 compatible 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 intersites cookie.
  • 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 considéré comme un scénario intersites.
  • La valeur SameSite=None n’est pas autorisée par la norme 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 sont 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 le mode de flux de la demande.

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

SameSite et Identity

L’Identity ASP.NET Core n’est en grande partie pas affectée par les cookies SameSite à l’exception des scénarios avancés tels que l’intégration IFrames ou OpenIdConnect.

Lorsque vous utilisez Identity, n’ajoutez pascookie de fournisseurs ou 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é :

Exemple Document
Pages .NET Core Razor ASP.NET Core 3.1 Razor Pages SameSite cookie exemple

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

.NET Core prend en charge la version préliminaire de la 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 sur Strict, Laxou None entraîne l’écriture de ces valeurs sur le réseau avec le cookie. La définition de SameSiteMode.Unspecified indique qu’aucun même Site 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 prend par défaut la valeur Unspecified, ce qui signifie qu’aucun attribut SameSite n’a été ajouté au cookie et que le client utilise son comportement par défaut (Lax pour les nouveaux navigateurs, Aucun pour les anciens). Le code suivant montre comment remplacer la cookie valeur SameSite par 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 remplacées n’ont pas changé.

Composant cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Authentication 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 et versions ultérieures fournit la prise en charge de 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 les exemples.

Dans ASP.NET Core 3.0 et versions ultérieures, les valeurs par défaut de SameSite ont été modifiées pour éviter les conflits avec les valeurs par défaut des clients 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 à l’aide de la norme provisoire 2016. La norme 2016 a été opt-in. ASP.NET Core a été opt-in en définissant plusieurs cookies sur Lax par défaut. Après avoir rencontré plusieurs problèmes d’authentification, la plupart de l’utilisation de SameSite a été désactivée.

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 appelent explicitement l’assertion SameSite=None pour activer la livraison intersites doivent être marqués comme Secure. None est une nouvelle entrée à refuser.
  • Est pris en charge par les correctifs émis pour ASP.NET Core 2.1, 2.2 et 3.0. ASP.NET Core 3.1 et versions ultérieures 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 2019

Prise en charge des navigateurs plus anciens

La norme SameSite 2016 a exigé que les valeurs inconnues soient traitées comme SameSite=Strict des valeurs. Les applications accessibles à partir de navigateurs plus anciens qui prennent en charge la norme SameSite 2016 peuvent s’interrompre 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 de connecter User-Agent logique spécifique.

Dans Program.cs, ajoutez du code qui appelle la UseCookiePolicy avant d’appeler l’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 :

Avertissement

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

  • Il ne doit pas être considéré comme complet.
  • Il n’est pas géré ou 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 qui peut accepter le nouveau comportement SameSite. Chrome, Firefox et Chromium Edge ont tous de nouveaux indicateurs de fonctionnalités d’adhésion qui peuvent être utilisés pour les tests. Une fois que votre application a appliqué les correctifs SameSite, testez-le 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 trompeurs, car une atténuation temporaire est en place. L’atténuation temporaire de Chrome 78+ autorise les cookies 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 nouveau comportement SameSite, basculez chrome://flags/#same-site-by-default-cookies sur Activé. Les versions antérieures de Chrome (75 et versions ultérieures) échouent avec le nouveau None paramètre. 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 Mises à jour SameSite des projets Chromium

Tester avec Safari

Safari 12 a strictement implémenté le brouillon précédent et échoue lorsque la nouvelle valeur None est dans un cookie. None est évité via le code de détection du navigateur Prise en charge des navigateurs plus anciens dans ce document. Testez les connexions de style de système d’exploitation basées sur Safari 12, Safari 13 et WebKit à l’aide de MSAL, ADAL ou n’importe quelle 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 indicateur d’adhésion pour tester le nouveau comportement de 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.

Testez avec Electron

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

Ressources supplémentaires

Exemple Document
Pages .NET Core Razor ASP.NET Core 3.1 Razor Pages SameSite cookie exemple

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

Exemple Document
Pages .NET Core Razor ASP.NET Core 3.1 Razor Pages SameSite cookie exemple

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

.NET Core 3.1 et versions ultérieures prennent en charge la version préliminaire de la 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 sur Strict, Lax ou None entraîne l’écriture de ces valeurs sur le réseau avec le cookie. Le fait de le définir comme étant égal à (SameSiteMode)(-1) indique qu’aucun attributSite identique 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 et versions ultérieures 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 site identique ne doit être envoyé avec . cookie

Utilisation de l’API avec SameSite

HttpContext.Response.Cookies.Append prend par défaut la valeur Unspecified, ce qui signifie qu’aucun attribut SameSite n’a été ajouté au cookie et que le client utilise son comportement par défaut (Lax pour les nouveaux navigateurs, Aucun pour les anciens). Le code suivant montre comment remplacer la cookie valeur SameSite par 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 remplacées n’ont pas changé.

Composant cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Authentication 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 et versions ultérieures fournit la prise en charge de 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 les exemples.

Dans ASP.NET Core 3.0 et versions ultérieures, les valeurs par défaut de SameSite ont été modifiées pour éviter les conflits avec les valeurs par défaut des clients 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 à l’aide de la norme provisoire 2016. La norme 2016 a été opt-in. ASP.NET Core a été opt-in en définissant plusieurs cookies sur Lax par défaut. Après avoir rencontré plusieurs problèmes d’authentification, la plupart de l’utilisation de SameSite a été désactivée.

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 appelent explicitement l’assertion SameSite=None pour activer la livraison intersites doivent être marqués comme Secure. None est une nouvelle entrée à refuser.
  • 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 2019

Prise en charge des navigateurs plus anciens

La norme SameSite 2016 a exigé que les valeurs inconnues soient traitées comme SameSite=Strict des valeurs. Les applications accessibles à partir de navigateurs plus anciens qui prennent en charge la norme SameSite 2016 peuvent s’interrompre 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 de connecter User-Agent logique spécifique.

Dans Startup.Configure, ajoutez du code qui appelle la UseCookiePolicy avant d’appeler l’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 :

Avertissement

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

  • Il ne doit pas être considéré comme complet.
  • Il n’est pas géré ou 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 qui peut accepter le nouveau comportement SameSite. Chrome, Firefox et Chromium Edge ont tous de nouveaux indicateurs de fonctionnalités d’adhésion qui peuvent être utilisés pour les tests. Une fois que votre application a appliqué les correctifs SameSite, testez-le 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 trompeurs, car une atténuation temporaire est en place. L’atténuation temporaire de Chrome 78+ autorise les cookies 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 nouveau comportement SameSite, basculez chrome://flags/#same-site-by-default-cookies sur Activé. Les versions antérieures de Chrome (75 et versions ultérieures) échouent avec le nouveau None paramètre. 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 Mises à jour SameSite des projets Chromium

Tester avec Safari

Safari 12 a strictement implémenté le brouillon précédent et échoue lorsque la nouvelle valeur None est dans un cookie. None est évité via le code de détection du navigateur Prise en charge des navigateurs plus anciens dans ce document. Testez les connexions de style de système d’exploitation basées sur Safari 12, Safari 13 et WebKit à l’aide de MSAL, ADAL ou n’importe quelle 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 indicateur d’adhésion pour tester le nouveau comportement de 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.

Testez avec Electron

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

Ressources supplémentaires

Exemple Document
Pages .NET Core Razor ASP.NET Core 3.1 Razor Pages SameSite cookie exemple

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

Exemple Document
.NET Core MVC ASP.NET Core 2.1 Exemple de site identique cookie MVC
PagesRazor .NET Core ASP.NET Core 2.1 Razor Pages SameSite cookie exemple

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 SameSite propriété interprète la valeurNone. 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 provoque l’émission de (SameSiteMode)(-1) 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 prend par défaut la valeur Unspecified, ce qui signifie qu’aucun attribut SameSite n’a été ajouté au cookie et que le client utilise son comportement par défaut (Lax pour les nouveaux navigateurs, Aucun pour les anciens). Le code suivant montre comment remplacer la cookie valeur SameSite par 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 remplacées n’ont pas changé.

Composant cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Authentication 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 à l’aide de la norme provisoire 2016. La norme 2016 a été opt-in. ASP.NET Core a été opt-in en définissant plusieurs cookies sur Lax par défaut. Après avoir rencontré plusieurs problèmes d’authentification, la plupart de l’utilisation de SameSite a été désactivée.

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 appelent explicitement l’assertion SameSite=None pour activer la livraison intersites doivent être marqués comme Secure. None est une nouvelle entrée à refuser.
  • 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 2019

Prise en charge des navigateurs plus anciens

La norme SameSite 2016 a exigé que les valeurs inconnues soient traitées comme SameSite=Strict des valeurs. Les applications accessibles à partir de navigateurs plus anciens qui prennent en charge la norme SameSite 2016 peuvent s’interrompre 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 de connecter User-Agent logique spécifique.

Dans Startup.Configure, ajoutez du code qui appelle la UseCookiePolicy avant d’appeler l’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 :

Avertissement

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

  • Il ne doit pas être considéré comme complet.
  • Il n’est pas géré ou 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 qui peut accepter le nouveau comportement SameSite. Chrome, Firefox et Chromium Edge ont tous de nouveaux indicateurs de fonctionnalités d’adhésion qui peuvent être utilisés pour les tests. Une fois que votre application a appliqué les correctifs SameSite, testez-le 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 trompeurs, car une atténuation temporaire est en place. L’atténuation temporaire de Chrome 78+ autorise les cookies 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 nouveau comportement SameSite, basculez chrome://flags/#same-site-by-default-cookies sur Activé. Les versions antérieures de Chrome (75 et versions ultérieures) échouent avec le nouveau None paramètre. 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 Mises à jour SameSite des projets Chromium

Tester avec Safari

Safari 12 a strictement implémenté le brouillon précédent et échoue lorsque la nouvelle valeur None est dans un cookie. None est évité via le code de détection du navigateur Prise en charge des navigateurs plus anciens dans ce document. Testez les connexions de style de système d’exploitation basées sur Safari 12, Safari 13 et WebKit à l’aide de MSAL, ADAL ou n’importe quelle 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 indicateur d’adhésion pour tester le nouveau comportement de 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.

Testez avec Electron

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

Ressources supplémentaires

Exemple Document
.NET Core MVC ASP.NET Core 2.1 Exemple de site identique cookie MVC
PagesRazor .NET Core ASP.NET Core 2.1 Razor Pages SameSite cookie exemple