Usare i cookie SameSite in ASP.NET Core

Di Rick Anderson

SameSite è uno standard in bozza dell'IETF progettato per fornire una certa protezione contro attacchi di falsificazione di richieste tra siti (CSRF). Originariamente elaborato nel 2016, il progetto di norma è stato aggiornato nel 2019. Lo standard aggiornato non è compatibile con lo standard precedente, con le differenze più evidenti:

  • I cookie senza intestazione SameSite vengono considerati come SameSite=Lax per impostazione predefinita.
  • SameSite=None deve essere usato per consentire l'uso di cookie tra siti.
  • Anche i cookie che asseriscono SameSite=None devono essere contrassegnati come Secure.
  • Le applicazioni che usano <iframe> possono riscontrare problemi con i cookie sameSite=Lax o sameSite=Strict perché <iframe> è considerato uno scenario cross-site.
  • Il valore SameSite=None non è consentito dallo standard 2016 e fa sì che alcune implementazioni considerino tali cookie come SameSite=Strict. Vedere Supporto per i browser meno recenti in questo documento.

L'impostazione SameSite=Lax funziona per la maggior parte dei cookie dell'applicazione. Per impostazione predefinita, alcune forme di autenticazione come OpenID Connect (OIDC) e WS-Federation usano reindirizzamenti basati su POST. I reindirizzamenti basati su POST attivano le protezioni del browser SameSite, quindi SameSite è disabilitato per questi componenti. La maggior parte degli accessi OAuth non è interessata a causa delle differenze nel modo in cui viene gestita la richiesta.

Ogni componente ASP.NET Core che genera cookie deve decidere se SameSite è appropriato.

SameSite e Identità

ASP.NET Core Identity non è in gran parte interessato dai cookie SameSite, ad eccezione di scenari avanzati come l'integrazione IFrames o OpenIdConnect.

Quando si usa Identity, non aggiungere provider di cookie o chiamare services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme), Identity si occupa di questo.

Codice di esempio di test SameSite

L'esempio seguente può essere scaricato e testato:

Sample Document
Razor Pages ASP.NET Core 3.1 Esempio di cookie Razor Pages SameSite

Supporto di .NET per l'attributo sameSite

.NET supporta la bozza di standard 2019 per SameSite. Gli sviluppatori possono controllare a livello di codice il valore dell'attributo sameSite usando la proprietà HttpCookie.SameSite. L'impostazione della SameSite proprietà su Strict, Laxo None comporta la scrittura di tali valori nella rete con il cookie. L'impostazione su SameSiteMode.Unspecified indica che non deve essere inviato alcun sameSite con il 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);
}

Utilizzo dell'API con SameSite

HttpContext.Response.Cookies.Append per impostazione predefinita è Unspecified, ovvero nessun attributo SameSite aggiunto al cookie e il client userà il comportamento predefinito (Lax per i nuovi browser, None per quelli precedenti). Il codice seguente illustra come modificare il valore SameSite del cookie in SameSiteMode.Lax:

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

Tutti i componenti ASP.NET Core che generano cookie sostituiscono le impostazioni predefinite precedenti con le impostazioni appropriate per i relativi scenari. I valori predefiniti precedenti sottoposti a override non sono stati modificati.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Autenticazione tramite cookie 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 o versione successiva offre il supporto SameSite seguente:

  • Ridefinisce il comportamento di SameSiteMode.None per emettere SameSite=None
  • Aggiunge un nuovo valore SameSiteMode.Unspecified per omettere l'attributo SameSite.
  • Per impostazione predefinita, tutte le API dei cookie usano Unspecified. Alcuni componenti che usano i cookie impostano valori più specifici per i relativi scenari. Per esempio, vedere la tabella sopra.

In ASP.NET Core 3.0 o versioni successive le impostazioni predefinite SameSite sono state modificate per evitare conflitti con impostazioni predefinite del client incoerenti. Le API seguenti hanno modificato il valore predefinito da SameSiteMode.Lax a -1 per evitare di emettere un attributo SameSite per questi cookie:

Cronologia e modifiche

Il supporto SameSite è stato implementato per la prima volta in ASP.NET Core nella versione 2.0 usando lo standard draft 2016. Lo standard 2016 era facoltativo. ASP.NET Core aderisce esplicitamente impostando diversi cookie su Lax per impostazione predefinita. Dopo aver riscontrato diversi problemi con l'autenticazione, la maggior parte degli utilizzi di SameSite è stata disabilitata.

Le patch sono state rilasciate a novembre 2019 per l'aggiornamento dallo standard 2016 allo standard 2019. La bozza 2019 della specifica SameSite:

  • Non è compatibile con le versioni precedenti della bozza del 2016. Per altre informazioni, vedere Supporto per browser meno recenti in questo documento.
  • Specifica che i cookie vengono considerati come SameSite=Lax per impostazione predefinita.
  • Specifica i cookie che asseriscono SameSite=None in modo esplicito per abilitare il recapito tra siti devono essere contrassegnati come Secure. None è una nuova voce per la disattivazione.
  • È supportato dalle patch rilasciate per ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 o versione successiva include supporto SameSite aggiuntivo.
  • Sarà attivato per impostazione predefinita in Chrome nel febbraio 2020. I browser hanno iniziato a passare a questo standard nel 2019.

API interessate dalla modifica dallo standard SameSite 2016 allo standard draft 2019

Supporto di browser meno recenti

Lo standard SameSite 2016 imponeva che i valori sconosciuti dovessero essere considerati come valori SameSite=Strict. Le app a cui si accede da browser meno recenti che supportano lo standard SameSite 2016 possono interrompersi quando ottengono una proprietà SameSite con un valore di None. Le app Web devono implementare il rilevamento del browser se intendono supportare browser meno recenti. ASP.NET Core non implementa il rilevamento del browser perché i valori degli agenti utente sono altamente volatili e cambiano frequentemente. Un punto di estensione in Microsoft.AspNetCore.CookiePolicy consente di integrare una logica specifica dello User-Agent.

In Program.csaggiungere codice che chiama UseCookiePolicy prima di chiamare UseAuthentication o qualsiasi metodo che scrive i cookie:

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

In Program.cs, aggiungere codice simile al codice evidenziato seguente:

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

Nell'esempio precedente è MyUserAgentDetectionLib.DisallowsSameSiteNone una libreria fornita dall'utente che rileva se l'agente utente non supporta SameSite None:

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

Il codice seguente illustra un metodo di esempio DisallowsSameSiteNone :

Warning

Il codice seguente è solo per dimostrazione:

  • Non deve essere considerato completo.
  • Non viene mantenuto o supportato.
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;
}

Testare le app per problemi SameSite

Le app che interagiscono con siti remoti, ad esempio tramite l'accesso di terze parti, devono:

Testare le app Web usando una versione client che può attivare esplicitamente il nuovo comportamento SameSite. Chrome, Firefox e Chromium Edge hanno tutti nuovi flag di funzionalità con attivazione facoltativa che possono essere usati per i test. Dopo che l'app ha applicato le patch SameSite, testarla con le versioni client precedenti, in particolare Safari. Per altre informazioni, vedere Supporto per i browser meno recenti in questo documento.

Prova con Chrome

Chrome 78+ offre risultati fuorvianti perché ha una mitigazione temporanea in atto. La mitigazione temporanea di Chrome 78+ consente i cookie creati da meno di due minuti. Chrome 76 o 77 con i flag di test appropriati abilitati fornisce risultati più accurati. Per testare il nuovo comportamento SameSite, impostare chrome://flags/#same-site-by-default-cookies su Abilitato. Le versioni precedenti di Chrome (75 e versioni precedenti) vengono segnalate come non funzionanti con la nuova impostazione None. Vedere Supporto per i browser meno recenti in questo documento.

Google non rende disponibili versioni chrome meno recenti. Seguire le istruzioni in Scaricare Chromium per testare le versioni precedenti di Chrome. Non scaricare Chrome dai collegamenti forniti cercando versioni precedenti di Chrome.

A partire da Canary versione 80.0.3975.0, la mitigazione temporanea Lax+POST può essere disabilitata a scopo di test usando il nuovo flag --enable-features=SameSiteDefaultChecksMethodRigorously per consentire il test di siti e servizi nello stato finale finale della funzionalità in cui è stata rimossa la mitigazione. Per altre informazioni, vedere The Chromium Projects SameSite Updates

Esegui un test con Safari

Safari 12 ha implementato rigorosamente la bozza precedente e si verifica un errore quando il nuovo valore di None è in un cookie. None viene evitato tramite il codice di rilevamento del browser Supporto per browser meno recenti in questo documento. Testare gli accessi in stile OS basati su Safari 12, Safari 13 e WebKit usando MSAL, ADAL o qualsiasi libreria in uso. Il problema dipende dalla versione del sistema operativo in uso. OSX Mojave (10.14) e iOS 12 sono noti per avere problemi di compatibilità con il nuovo comportamento SameSite. L'aggiornamento del sistema operativo a OSX Catalina (10.15) o iOS 13 risolve il problema. Safari non dispone attualmente di un flag opt-in per testare il nuovo comportamento della specifica.

Test con Firefox

Il supporto di Firefox per il nuovo standard può essere testato sulla versione 68+ attivando l'opzione nella pagina about:config con il flag di funzionalità network.cookie.sameSite.laxByDefault. Non sono stati segnalati problemi di compatibilità con le versioni precedenti di Firefox.

Testare con il browser Edge

Edge supporta il precedente standard SameSite. Edge versione 44 non presenta problemi di compatibilità noti con il nuovo standard.

Test con edge (Chromium)

I flag SameSite vengono impostati nella edge://flags/#same-site-by-default-cookies pagina. Non sono stati rilevati problemi di compatibilità con Edge Chromium.

Test con Elettrone

Le versioni di Electron includono versioni precedenti di Chromium. Ad esempio, la versione di Electron usata da Teams è Chromium 66, che mostra il comportamento precedente. È necessario eseguire test di compatibilità personalizzati con la versione di Electron usato dal prodotto. Vedere Supporto per i browser meno recenti nella sezione seguente.

Risorse aggiuntive

Sample Document
Razor Pages ASP.NET Core 3.1 Esempio di cookie Razor Pages SameSite

L'esempio seguente può essere scaricato e testato:

Sample Document
Razor Pages ASP.NET Core 3.1 Esempio di cookie Razor Pages SameSite

Supporto di .NET Core per l'attributo sameSite

.NET Core 3.1 o versione successiva supporta lo standard draft 2019 per SameSite. Gli sviluppatori possono controllare a livello di codice il valore dell'attributo sameSite usando la proprietà HttpCookie.SameSite. Se si imposta la SameSite proprietà su Strict, Lax o None, tali valori verranno scritti nella rete con il cookie. Impostarlo su (SameSiteMode)(-1) indica che non deve essere incluso alcun attributo SameSite con il 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 o versione successiva supporta i valori SameSite aggiornati e aggiunge un valore enum aggiuntivo alla enum SameSiteMode.UnspecifiedSameSiteMode. Questo nuovo valore indica che non deve essere inviato alcun sameSite con il cookie.

Utilizzo dell'API con SameSite

HttpContext.Response.Cookies.Append per impostazione predefinita è Unspecified, ovvero nessun attributo SameSite aggiunto al cookie e il client userà il comportamento predefinito (Lax per i nuovi browser, None per quelli meno recenti). Il codice seguente illustra come modificare il valore SameSite del cookie in SameSiteMode.Lax:

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

Tutti i componenti di ASP.NET Core che generano cookie sostituiscono le impostazioni predefinite precedenti con le impostazioni appropriate per i relativi scenari. I valori predefiniti precedenti sottoposti a override non sono stati modificati.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Autenticazione tramite cookie 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 o versione successiva offre il supporto SameSite seguente:

  • Ridefinisce il comportamento di SameSiteMode.None per emettere SameSite=None
  • Aggiunge un nuovo valore SameSiteMode.Unspecified per omettere l'attributo SameSite.
  • Per impostazione predefinita, tutte le API dei cookie usano Unspecified. Alcuni componenti che usano i cookie impostano valori più specifici per i relativi scenari. Vedere la tabella sopra per alcuni esempi.

In ASP.NET Core 3.0 o versioni successive le impostazioni predefinite SameSite sono state modificate per evitare conflitti con impostazioni predefinite del client incoerenti. Le API seguenti hanno modificato il valore predefinito da SameSiteMode.Lax a -1 per evitare di emettere un attributo SameSite per questi cookie:

Cronologia e modifiche

Il supporto sameSite è stato implementato per la prima volta in ASP.NET Core nella versione 2.0 usando lo standard draft 2016. Lo standard 2016 era facoltativo. ASP.NET Core abilita esplicitamente l'impostazione di diversi cookie su Lax per impostazione predefinita. Dopo aver riscontrato diversi problemi con l'autenticazione, la maggior parte degli usi di SameSite è stata disabilitata.

Le patch sono state rilasciate a novembre 2019 per l'aggiornamento dallo standard 2016 allo standard 2019. La bozza 2019 della specifica SameSite:

  • Non è compatibile con le versioni precedenti della bozza del 2016. Per altre informazioni, vedere Supporto per browser meno recenti in questo documento.
  • Specifica che i cookie vengono considerati come SameSite=Lax per impostazione predefinita.
  • Specifica i cookie che dichiarano esplicitamente SameSite=None per abilitare il recapito tra siti devono essere contrassegnati come Secure. None è una nuova voce per rinunciare esplicitamente.
  • È supportato dalle patch rilasciate per ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 include un supporto SameSite aggiuntivo.
  • È pianificata l'abilitazione per impostazione predefinita da Chrome nel febbraio 2020. I browser hanno iniziato a passare a questo standard nel 2019.

API interessate dalla modifica dallo standard SameSite 2016 allo standard draft 2019

Supporto di browser meno recenti

Lo standard SameSite 2016 ha imposto che i valori sconosciuti debbano essere considerati come valori SameSite=Strict. Le app a cui si accede da browser meno recenti che supportano lo standard SameSite 2016 possono interrompersi quando ottengono una proprietà SameSite con un valore di None. Le app Web devono implementare il rilevamento del browser se intendono supportare browser meno recenti. ASP.NET Core non implementa il rilevamento del browser perché i valori degli agenti utente sono altamente volatili e cambiano frequentemente. Un punto di estensione in Microsoft.AspNetCore.CookiePolicy consente di collegare una logica specifica dello User-Agent.

In Startup.Configureaggiungere codice che chiama UseCookiePolicy prima di chiamare UseAuthentication o qualsiasi metodo che scrive i cookie:

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

In Startup.ConfigureServicesaggiungere codice simile al seguente:

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

Nell'esempio precedente è MyUserAgentDetectionLib.DisallowsSameSiteNone una libreria fornita dall'utente che rileva se l'agente utente non supporta SameSite None:

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

Il codice seguente illustra un metodo di esempio DisallowsSameSiteNone :

Warning

Il codice seguente è solo per dimostrazione:

  • Non deve essere considerato completo.
  • Non viene mantenuto né supportato.
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;
}

Test app per problemi con SameSite

Le app che interagiscono con siti remoti, ad esempio tramite l'accesso di terze parti, devono:

Testare le app Web usando una versione client che consente di attivare esplicitamente il nuovo comportamento SameSite. Chrome, Firefox e Chromium Edge hanno tutti nuovi flag delle funzionalità da attivare esplicitamente che possono essere usati per i test. Dopo che l'app ha applicato le patch SameSite, testarla con le versioni client precedenti, in particolare Safari. Per altre informazioni, vedere Supporto per browser meno recenti in questo documento.

Prova con Chrome

Chrome 78+ offre risultati fuorvianti perché ha una mitigazione temporanea attiva. La mitigazione temporanea di Chrome 78+ consente i cookie con meno di due minuti. Chrome 76 o 77 con i flag di test appropriati abilitati fornisce risultati più accurati. Per testare il nuovo comportamento SameSite, chrome://flags/#same-site-by-default-cookiesimpostare l'opzione su Abilitato. Le versioni precedenti di Chrome (75 e precedenti) sono segnalate come non funzionanti con la nuova impostazione None. Vedere Supporto per i browser meno recenti in questo documento.

Google non rende disponibili versioni di Chrome meno recenti. Seguire le istruzioni in Scaricare Chromium per testare le versioni precedenti di Chrome. Non scaricare Chrome dai collegamenti forniti cercando versioni precedenti di Chrome.

A partire da Canary versione 80.0.3975.0, la mitigazione temporanea Lax+POST può essere disabilitata a scopo di test usando il nuovo flag --enable-features=SameSiteDefaultChecksMethodRigorously per consentire il test di siti e servizi nello stato finale finale della funzionalità in cui è stata rimossa la mitigazione. Per altre informazioni, vedere The Chromium Projects SameSite Updates

Esegui il test con Safari

Safari 12 ha implementato rigorosamente la bozza precedente e si verifica un errore quando il nuovo valore di None è in un cookie. None viene evitato tramite il codice di rilevamento del browser Supporto dei browser meno recenti in questo documento. Testare gli accessi in stile OS basati su Safari 12, Safari 13 e WebKit usando MSAL, ADAL o qualsiasi libreria in uso. Il problema dipende dalla versione del sistema operativo sottostante. OSX Mojave (10.14) e iOS 12 sono noti per avere problemi di compatibilità con il nuovo comportamento SameSite. L'aggiornamento del sistema operativo a OSX Catalina (10.15) o iOS 13 risolve il problema. Safari non dispone attualmente di un flag di attivazione per testare il nuovo comportamento della specifica.

Prova con Firefox

Il supporto di Firefox per il nuovo standard può essere testato a partire dalla versione 68+ attivandolo nella pagina about:config con il flag di funzionalità network.cookie.sameSite.laxByDefault. Non sono stati segnalati problemi di compatibilità con le versioni precedenti di Firefox.

Testare con il browser Edge

Edge supporta il vecchio standard SameSite. Edge versione 44 non presenta problemi di compatibilità noti con il nuovo standard.

Test con edge (Chromium)

I flag SameSite vengono impostati nella edge://flags/#same-site-by-default-cookies pagina. Non sono stati rilevati problemi di compatibilità con Edge Chromium.

Test con Elettrone

Le versioni di Electron includono versioni precedenti di Chromium. Ad esempio, la versione di Electron usata da Teams è Chromium 66, che mostra il comportamento precedente. È necessario eseguire test di compatibilità personalizzati con la versione di Electron usato dal prodotto. Vedere Supporto per i browser meno recenti nella sezione seguente.

Risorse aggiuntive

Sample Document
Razor Pages ASP.NET Core 3.1 Esempio di cookie Razor Pages SameSite

È possibile scaricare e testare gli esempi seguenti:

Sample Document
MVC Esempio di cookie SameSite MVC 2.1 ASP.NET Core
Razor Pages ASP.NET Core 2.1 Esempio di cookie Razor Pages SameSite

Modifiche al comportamento delle patch di dicembre

La modifica del comportamento specifica per .NET Framework e .NET Core 2.1 è il modo in cui la SameSite proprietà interpreta il None valore. Prima della patch un valore di None significava "Non emettere affatto l'attributo", dopo la patch significa "Emettere l'attributo con un valore di None". Dopo la patch un SameSite valore di (SameSiteMode)(-1) fa sì che l'attributo non venga generato.

Il valore SameSite predefinito per l'autenticazione basata su form e i cookie di stato della sessione è stato modificato da None a Lax.

Utilizzo dell'API con SameSite

HttpContext.Response.Cookies.Append per impostazione predefinita è Unspecified, ovvero nessun attributo SameSite aggiunto al cookie e il client userà il comportamento predefinito (Lax per i nuovi browser, None per quelli precedenti). Il codice seguente illustra come modificare il valore SameSite del cookie in SameSiteMode.Lax:

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

Tutti i componenti di ASP.NET Core che generano cookie sostituiscono le impostazioni predefinite precedenti con le impostazioni appropriate per i relativi scenari. I valori predefiniti precedenti sottoposti a override non sono stati modificati.

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

Cronologia e modifiche

Il supporto sameSite è stato implementato per la prima volta in ASP.NET Core nella versione 2.0 usando lo standard draft 2016. Lo standard 2016 era facoltativo. ASP.NET Core aderisce esplicitamente impostando per impostazione predefinita diversi cookie in Lax. Dopo aver riscontrato diversi problemi con l'autenticazione, la maggior parte dell'utilizzo di SameSite è stata disabilitata.

Le patch sono state rilasciate a novembre 2019 per l'aggiornamento dallo standard 2016 allo standard 2019. La bozza 2019 della specifica SameSite:

  • Non è compatibile con la bozza del 2016. Per altre informazioni, vedere Supporto per i browser meno recenti in questo documento.
  • Specifica che i cookie vengono considerati come SameSite=Lax per impostazione predefinita.
  • I cookie che dichiarano esplicitamente SameSite=None per abilitare il recapito tra siti devono essere contrassegnati come Secure. None è una nuova voce per annullare l'adesione.
  • È supportato dalle patch rilasciate per ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 include un supporto SameSite aggiuntivo.
  • È pianificato che venga abilitata da Chrome per impostazione predefinita nel febbraio 2020. I browser hanno iniziato a passare a questo standard nel 2019.

API interessate dalla modifica dallo standard SameSite 2016 allo standard draft 2019

Supporto per browser meno recenti

Lo standard SameSite 2016 impone che i valori sconosciuti debbano essere considerati come SameSite=Strict valori. Le app a cui si accede da browser meno recenti che supportano lo standard SameSite 2016 possono interrompersi quando ottengono una proprietà SameSite con un valore di None. Le app Web devono implementare il rilevamento del browser se intendono supportare browser meno recenti. ASP.NET Core non implementa il rilevamento del browser perché i valori degli agenti utente sono altamente volatili e cambiano frequentemente. Un punto di estensione in Microsoft.AspNetCore.CookiePolicy consente di integrare una logica specifica del User-Agent.

In Startup.Configureaggiungere codice che chiama UseCookiePolicy prima di chiamare UseAuthentication o qualsiasi metodo che scrive i cookie:

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

In Startup.ConfigureServices, aggiungere codice simile al seguente:

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

    }
}

Nell'esempio precedente è MyUserAgentDetectionLib.DisallowsSameSiteNone una libreria fornita dall'utente che rileva se l'agente utente non supporta SameSite None:

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

Il codice seguente illustra un metodo di esempio DisallowsSameSiteNone :

Warning

Il codice seguente è solo per dimostrazione:

  • Non deve essere considerato completo.
  • Non è mantenuto né supportato.
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;
}

Verificare le app per problemi SameSite

Le app che interagiscono con siti remoti, ad esempio tramite l'accesso di terze parti, devono:

Testare le app Web usando una versione client che può acconsentire esplicitamente al nuovo comportamento SameSite. Chrome, Firefox e Chromium Edge hanno tutti nuovi flag di funzionalità attivabili su richiesta che possono essere usati per i test. Dopo che l'app ha applicato le patch SameSite, testala con le versioni client precedenti, in particolare Safari. Per altre informazioni, vedere Supporto per browser meno recenti in questo documento.

Prova con Chrome

Chrome 78+ offre risultati fuorvianti perché ha una mitigazione temporanea attiva. La mitigazione temporanea di Chrome 78+ consente i cookie creati da meno di due minuti. Chrome 76 o 77 con i flag di test appropriati abilitati fornisce risultati più accurati. Per testare il nuovo comportamento SameSite, impostare chrome://flags/#same-site-by-default-cookies su Abilitato. Le versioni precedenti di Chrome (75 e precedenti) vengono segnalate come non funzionanti con la nuova impostazione None. Vedere Supporto per browser meno recenti in questo documento.

Google non rende disponibili versioni chrome meno recenti. Seguire le istruzioni in Scaricare Chromium per testare le versioni precedenti di Chrome. Non scaricare Chrome dai collegamenti forniti cercando versioni precedenti di Chrome.

A partire da Canary versione 80.0.3975.0, la mitigazione temporanea Lax+POST può essere disabilitata a scopo di test usando il nuovo flag --enable-features=SameSiteDefaultChecksMethodRigorously per consentire il test di siti e servizi nello stato finale finale della funzionalità in cui è stata rimossa la mitigazione. Per altre informazioni, vedere The Chromium Projects SameSite Updates

Eseguire un test con Safari

Safari 12 ha implementato rigorosamente la bozza precedente e si verifica un errore quando il nuovo valore di None è in un cookie. None viene evitato tramite il codice di rilevamento del browser Supporto dei browser meno recenti in questo documento. Testare gli accessi in stile sistema operativo basati su Safari 12, Safari 13 e WebKit usando MSAL, ADAL o qualsiasi libreria in uso. Il problema dipende dalla versione del sistema operativo sottostante. OSX Mojave (10.14) e iOS 12 sono noti per avere problemi di compatibilità con il nuovo comportamento SameSite. L'aggiornamento del sistema operativo a OSX Catalina (10.15) o iOS 13 risolve il problema. Safari non dispone attualmente di un flag di attivazione per testare il nuovo comportamento della specifica.

Prova con Firefox

Il supporto di Firefox per il nuovo standard può essere testato sulla versione 68+ attivandolo nella pagina about:config con il flag network.cookie.sameSite.laxByDefault. Non sono stati segnalati problemi di compatibilità con le versioni precedenti di Firefox.

Esegui il test con il browser Edge

Edge supporta il vecchio standard SameSite. Edge versione 44 non presenta problemi di compatibilità noti con il nuovo standard.

Test con edge (Chromium)

I flag SameSite vengono impostati nella edge://flags/#same-site-by-default-cookies pagina. Non sono stati rilevati problemi di compatibilità con Edge Chromium.

Test con Elettrone

Le versioni di Electron includono versioni precedenti di Chromium. Ad esempio, la versione di Electron usata da Teams è Chromium 66, che mostra il comportamento precedente. È necessario eseguire test di compatibilità personalizzati con la versione di Electron usato dal prodotto. Vedere Supporto per browser meno recenti nella sezione seguente.

Risorse aggiuntive

Sample Document
MVC Esempio di cookie SameSite MVC 2.1 ASP.NET Core
Razor Pages ASP.NET Core 2.1 Esempio di cookie Razor Pages SameSite