Partilhar via


Trabalhar com cookies SameSite no ASP.NET Core

Por Rick Anderson

O SameSite é um projeto de padrão IETF projetado para fornecer alguma proteção contra ataques de falsificação de solicitação entre sites (CSRF). Originalmente redigido em 2016, o projeto de norma foi atualizado em 2019. O padrão atualizado não é compatível com o padrão anterior, com as seguintes diferenças sendo as mais percetíveis:

  • Os cookies sem cabeçalho SameSite são tratados como SameSite=Lax por padrão.
  • SameSite=None deve ser utilizado para permitir a utilização entre diferentes sites cookie.
  • Os cookies que afirmam SameSite=None também devem ser marcados como Secure.
  • Os aplicativos que usam <iframe> podem ter problemas com sameSite=Lax ou sameSite=Strict cookies porque <iframe> são tratados como cenários entre sites.
  • O valor SameSite=None não é permitido pelo padrão de 2016 e faz com que algumas implementações tratem cookies como SameSite=Strict. Consulte Suporte a navegadores mais antigos neste documento.

A SameSite=Lax configuração funciona para a maioria dos cookies de aplicativos. Algumas formas de autenticação como OpenID Connect (OIDC) e WS-Federation por padrão utilizam redirecionamentos baseados em POST. Os redirecionamentos baseados em POST acionam as proteções do navegador SameSite, portanto, o SameSite está desativado para esses componentes. A maioria dos logins OAuth não são afetados devido a diferenças na forma como a solicitação flui.

Cada componente ASP.NET Core que emite cookies precisa decidir se o SameSite é apropriado.

SameSite e Identity

ASP.NET Core Identity não é afetado pelos cookies do SameSite , exceto para cenários avançados, como IFrames ou OpenIdConnect integração.

Ao usar Identity, não adicione quaisquer provedores ou chame , cookie cuida disso.

Código de exemplo de teste SameSite

O exemplo a seguir pode ser baixado e testado:

Sample Document
Razor Páginas ASP.NET Exemplo do Core 3.1 Razor Pages SameSite cookie

Suporte .NET para o atributo sameSite

O .NET é compatível com o projeto de norma de 2019 para SameSite. Os desenvolvedores são capazes de controlar programaticamente o valor do atributo sameSite usando a HttpCookie.SameSite propriedade. Definir a SameSite propriedade como Strict, Laxou None resulta na gravação desses valores na rede com o cookie. A configuração para SameSiteMode.Unspecified indica que o atributo sameSite não deve ser enviado com o 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);
}

Uso da API com o SameSite

HttpContext.Response.Cookies.Append assume como padrão Unspecified, o que significa que nenhum atributo SameSite foi adicionado ao cookie e o cliente usará seu comportamento padrão (Lax para novos navegadores, Nenhum para os antigos). O código a seguir mostra como alterar o cookie valor SameSite para SameSiteMode.Lax:

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

Todos os componentes principais ASP.NET que emitem cookies substituem os padrões anteriores com configurações apropriadas para seus cenários. Os valores padrão anteriores substituídos não foram alterados.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery OpçõesAntifalsificação.Cookie Strict
Cookie Autenticação CookiesAuthenticationOptions.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 posterior fornece o seguinte suporte ao SameSite:

  • Redefine o comportamento de SameSiteMode.None para emitir SameSite=None
  • Adiciona um novo valor SameSiteMode.Unspecified para omitir o atributo SameSite.
  • Todas as APIs de cookies são padronizadas como Unspecified. Alguns componentes que utilizam cookies definem valores mais específicos para os seus cenários. Veja exemplos na tabela acima.

No ASP.NET Core 3.0 ou posterior, os padrões do SameSite foram alterados para evitar conflitos com padrões de cliente inconsistentes. As seguintes APIs alteraram o padrão de SameSiteMode.Lax para -1 para evitar a emissão de um atributo SameSite para esses cookies.

História e mudanças

O suporte ao SameSite foi implementado pela primeira vez no ASP.NET Core em 2.0 usando o padrão de rascunho de 2016. A norma de 2016 era opcional. ASP.NET Core optou por participar definindo vários cookies como Lax por padrão. Depois de encontrar vários problemas com a autenticação, a maioria do uso do SameSite foi desativada.

Os patches foram emitidos em novembro de 2019 para atualizar do padrão de 2016 para o padrão de 2019. O rascunho de 2019 da especificação SameSite:

  • Não é retrocompatível com o projeto de 2016. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.
  • Especifica que os cookies são tratados como SameSite=Lax por padrão.
  • Os cookies que afirmam explicitamente SameSite=None devem ser marcados como Secure para permitir a entrega entre sites. None é uma nova entrada para optar por não participar.
  • É suportado por patches emitidos para ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 ou posterior tem suporte adicional ao SameSite.
  • Está programado para ser ativado pelo Chrome por padrão em fevereiro de 2020. Os navegadores começaram a migrar para esse padrão em 2019.

APIs afetadas pela mudança do padrão de rascunho SameSite de 2016 para o padrão de rascunho de 2019

Suporte a navegadores mais antigos

O padrão SameSite de 2016 determinou que valores desconhecidos devem ser tratados como SameSite=Strict valores. As aplicações acedidas a partir de navegadores mais antigos que suportam o padrão SameSite de 2016 podem deixar de funcionar quando recebem uma propriedade SameSite com um valor de None. Os aplicativos Web devem implementar a deteção de navegador se pretenderem oferecer suporte a navegadores mais antigos. ASP.NET Core não implementa a deteção do navegador porque User-Agents valores são altamente voláteis e mudam com frequência. Um ponto de extensão em Microsoft.AspNetCore.CookiePolicy permite integrar lógica específica de User-Agent.

No Program.cs, adicione o código que chama UseCookiePolicy antes de chamar UseAuthentication ou qualquer método que escreva 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();

No Program.cs, adicione um código semelhante ao seguinte código realçado:

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

No exemplo anterior, MyUserAgentDetectionLib.DisallowsSameSiteNone é uma biblioteca fornecida pelo usuário que deteta se o agente do usuário não suporta SameSite None:

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

O código a seguir mostra um método de exemplo DisallowsSameSiteNone :

Warning

O código a seguir é apenas para demonstração:

  • Não deve ser considerado completo.
  • Não é mantido ou apoiado.
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;
}

Testar aplicativos para problemas do SameSite

Os aplicativos que interagem com sites remotos, como por meio de login de terceiros, precisam:

Teste aplicativos Web usando uma versão de cliente que pode aceitar o novo comportamento SameSite. Chrome, Firefox e Chromium Edge têm novos sinalizadores de recursos de aceitação que podem ser usados para testes. Depois de o aplicativo aplicar os patches do SameSite, teste com versões mais antigas do cliente, especialmente o Safari. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.

Teste com o Chrome

O Chrome 78+ dá resultados enganosos porque tem uma atenuação temporária em vigor. A atenuação temporária do Chrome 78+ permite cookies com menos de dois minutos. O Chrome 76 ou 77 com os sinalizadores de teste apropriados ativados fornece resultados mais precisos. Para testar o novo comportamento SameSite, alterne chrome://flags/#same-site-by-default-cookies para Enabled. As versões mais antigas do Chrome (75 e inferiores) apresentam falhas com a nova None definição. Consulte Suporte a navegadores mais antigos neste documento.

A Google não disponibiliza versões mais antigas do chrome. Siga as instruções em Transferir o Chromium para testar versões mais antigas do Chrome. Não transfira o Chrome a partir de hiperligações fornecidas ao procurar por versões antigas do Chrome.

A partir da versão 80.0.3975.0Canary, a mitigação temporária Lax+POST pode ser desativada para fins de teste usando o novo sinalizador --enable-features=SameSiteDefaultChecksMethodRigorously para permitir o teste de locais e serviços no eventual estado final do recurso em que a mitigação foi removida. Para obter mais informações, consulte The Chromium Projects SameSite Updates

Teste com o Safari

O Safari 12 implementou estritamente o rascunho anterior e falha quando o novo valor None está num cookie arquivo. None é evitada usando o código de detecção de navegadores Suporte para navegadores mais antigos neste documento. Teste os logins ao estilo do sistema operativo baseados no Safari 12, Safari 13 e WebKit usando MSAL, ADAL ou qualquer biblioteca que estejas a utilizar. O problema depende da versão subjacente do sistema operacional. O OSX Mojave (10.14) e o iOS 12 são conhecidos por terem problemas de compatibilidade com o novo comportamento do SameSite. Atualizar o sistema operacional para OSX Catalina (10.15) ou iOS 13 corrige o problema. Atualmente, o Safari não tem um sinalizador de aceitação para testar o novo comportamento das especificações.

Teste com o Firefox

O suporte do Firefox para o novo padrão pode ser testado na versão 68+, ativando na página about:config com a bandeira de recurso network.cookie.sameSite.laxByDefault. Não houve relatos de problemas de compatibilidade com versões mais antigas do Firefox.

Teste com o navegador Edge

O Edge suporta o antigo padrão SameSite. A versão 44 do Edge não tem problemas de compatibilidade conhecidos com o novo padrão.

Teste com Edge (Chromium)

Os sinalizadores SameSite são definidos na edge://flags/#same-site-by-default-cookies página. Não foram detetados problemas de compatibilidade com o Edge Chromium.

Teste com Electron

As versões do Electron incluem versões mais antigas do Chromium. Por exemplo, a versão usada Electron pelo Teams é o Chromium 66, que exibe o comportamento mais antigo. Você deve realizar seus próprios testes de compatibilidade com a versão que o Electron seu produto utiliza. Consulte Suporte a navegadores mais antigos na seção a seguir.

Recursos adicionais

Sample Document
Razor Páginas ASP.NET Exemplo do Core 3.1 Razor Pages SameSite cookie

O exemplo a seguir pode ser baixado e testado:

Sample Document
Razor Páginas ASP.NET Exemplo do Core 3.1 Razor Pages SameSite cookie

Suporte do .NET Core para o atributo sameSite

O .NET Core 3.1 ou versão posterior suporta o rascunho do padrão de 2019 para SameSite. Os desenvolvedores são capazes de controlar programaticamente o valor do atributo sameSite usando a HttpCookie.SameSite propriedade. Definir a SameSite propriedade como Strict, Lax ou None resulta na gravação desses valores na rede com o cookie. Definir como igual a (SameSiteMode)(-1) indica que nenhum atributo sameSite deve ser incluído na rede com 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);

O .NET Core 3.1 ou posterior oferece suporte aos valores SameSite atualizados e adiciona um valor SameSiteMode.Unspecified enum extra ao SameSiteMode enum. Este novo valor indica que nenhum sameSite deve ser enviado com o cookie.

Uso da API com o SameSite

HttpContext.Response.Cookies.Append assume como padrão Unspecified, o que significa que nenhum atributo SameSite foi adicionado ao cookie e o cliente usará seu comportamento padrão (Lax para novos navegadores, Nenhum para os antigos). O código a seguir mostra como alterar o cookie valor SameSite para SameSiteMode.Lax:

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

Todos os componentes principais ASP.NET que emitem cookies substituem os padrões anteriores com configurações apropriadas para seus cenários. Os valores padrão anteriores substituídos não foram alterados.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntifalsificaçãoOptions.Cookie Strict
Cookie Autenticação CookiesAuthenticationOptions.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 posterior fornece o seguinte suporte ao SameSite:

  • Redefine o comportamento de SameSiteMode.None para emitir SameSite=None
  • Adiciona um novo valor SameSiteMode.Unspecified para omitir o atributo SameSite.
  • Todas as APIs de cookies são padronizadas como Unspecified. Alguns componentes que utilizam cookies definem valores mais específicos para os seus cenários. Veja exemplos na tabela acima.

No ASP.NET Core 3.0 ou posterior, os padrões do SameSite foram alterados para evitar conflitos com padrões de cliente inconsistentes. As seguintes APIs alteraram o padrão de SameSiteMode.Lax para -1 para evitar a emissão de um atributo SameSite para esses cookies.

História e mudanças

O suporte ao SameSite foi implementado pela primeira vez no ASP.NET Core em 2.0 usando o padrão de rascunho de 2016. A norma de 2016 era opcional. ASP.NET Core optou por participar definindo vários cookies como Lax por padrão. Depois de encontrar vários problemas com a autenticação, a maioria do uso do SameSite foi desativada.

Os patches foram emitidos em novembro de 2019 para atualizar do padrão de 2016 para o padrão de 2019. O rascunho de 2019 da especificação SameSite:

  • Não é retrocompatível com o projeto de 2016. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.
  • Especifica que os cookies são tratados como SameSite=Lax por padrão.
  • Os cookies que afirmam explicitamente SameSite=None devem ser marcados como Secure para permitir a entrega entre sites. None é uma nova entrada para optar por não participar.
  • É suportado por patches emitidos para ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 tem suporte adicional ao SameSite.
  • Está programado para ser ativado pelo Chrome por padrão em fevereiro de 2020. Os navegadores começaram a migrar para esse padrão em 2019.

APIs afetadas pela mudança do padrão de rascunho SameSite de 2016 para o padrão de rascunho de 2019

Suporte a navegadores mais antigos

O padrão SameSite de 2016 determinou que valores desconhecidos devem ser tratados como SameSite=Strict valores. As aplicações acedidas a partir de navegadores mais antigos que suportam o padrão SameSite de 2016 podem deixar de funcionar quando recebem uma propriedade SameSite com um valor de None. Os aplicativos Web devem implementar a deteção de navegador se pretenderem oferecer suporte a navegadores mais antigos. ASP.NET Core não implementa a deteção do navegador porque User-Agents valores são altamente voláteis e mudam com frequência. Um ponto de extensão em Microsoft.AspNetCore.CookiePolicy permite integrar lógica específica de User-Agent.

No Startup.Configure, adicione o código que chama UseCookiePolicy antes de chamar UseAuthentication ou qualquer método que escreva 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();
    });
}

No Startup.ConfigureServices, adicione um código semelhante ao seguinte:

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

No exemplo anterior, MyUserAgentDetectionLib.DisallowsSameSiteNone é uma biblioteca fornecida pelo usuário que deteta se o agente do usuário não suporta SameSite None:

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

O código a seguir mostra um método de exemplo DisallowsSameSiteNone :

Warning

O código a seguir é apenas para demonstração:

  • Não deve ser considerado completo.
  • Não é mantido ou apoiado.
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;
}

Testar aplicativos para problemas do SameSite

Os aplicativos que interagem com sites remotos, como por meio de login de terceiros, precisam:

Teste aplicativos Web usando uma versão de cliente que pode aceitar o novo comportamento SameSite. Chrome, Firefox e Chromium Edge têm novos sinalizadores de recursos de aceitação que podem ser usados para testes. Depois de o aplicativo aplicar os patches do SameSite, teste com versões mais antigas do cliente, especialmente o Safari. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.

Teste com o Chrome

O Chrome 78+ dá resultados enganosos porque tem uma atenuação temporária em vigor. A atenuação temporária do Chrome 78+ permite cookies com menos de dois minutos. O Chrome 76 ou 77 com os sinalizadores de teste apropriados ativados fornece resultados mais precisos. Para testar o novo comportamento SameSite, alterne chrome://flags/#same-site-by-default-cookies para Enabled. As versões mais antigas do Chrome (75 e inferiores) apresentam falhas com a nova None definição. Consulte Suporte a navegadores mais antigos neste documento.

A Google não disponibiliza versões mais antigas do chrome. Siga as instruções em Transferir o Chromium para testar versões mais antigas do Chrome. Não transfira o Chrome a partir de hiperligações fornecidas ao procurar por versões antigas do Chrome.

A partir da versão 80.0.3975.0Canary, a mitigação temporária Lax+POST pode ser desativada para fins de teste usando o novo sinalizador --enable-features=SameSiteDefaultChecksMethodRigorously para permitir o teste de locais e serviços no eventual estado final do recurso em que a mitigação foi removida. Para obter mais informações, consulte The Chromium Projects SameSite Updates

Teste com o Safari

O Safari 12 implementou estritamente o rascunho anterior e falha quando o novo valor None está num cookie arquivo. None é evitada usando o código de detecção de navegadores Suporte para navegadores mais antigos neste documento. Teste os logins ao estilo do sistema operativo baseados no Safari 12, Safari 13 e WebKit usando MSAL, ADAL ou qualquer biblioteca que estejas a utilizar. O problema depende da versão subjacente do sistema operacional. O OSX Mojave (10.14) e o iOS 12 são conhecidos por terem problemas de compatibilidade com o novo comportamento do SameSite. Atualizar o sistema operacional para OSX Catalina (10.15) ou iOS 13 corrige o problema. Atualmente, o Safari não tem um sinalizador de aceitação para testar o novo comportamento das especificações.

Teste com o Firefox

O suporte do Firefox para o novo padrão pode ser testado na versão 68+, ativando na página about:config com a bandeira de recurso network.cookie.sameSite.laxByDefault. Não houve relatos de problemas de compatibilidade com versões mais antigas do Firefox.

Teste com o navegador Edge

O Edge suporta o antigo padrão SameSite. A versão 44 do Edge não tem problemas de compatibilidade conhecidos com o novo padrão.

Teste com Edge (Chromium)

Os sinalizadores SameSite são definidos na edge://flags/#same-site-by-default-cookies página. Não foram detetados problemas de compatibilidade com o Edge Chromium.

Teste com Electron

As versões do Electron incluem versões mais antigas do Chromium. Por exemplo, a versão usada Electron pelo Teams é o Chromium 66, que exibe o comportamento mais antigo. Você deve realizar seus próprios testes de compatibilidade com a versão que o Electron seu produto utiliza. Consulte Suporte a navegadores mais antigos na seção a seguir.

Recursos adicionais

Sample Document
Razor Páginas ASP.NET Exemplo do Core 3.1 Razor Pages SameSite cookie

Os seguintes exemplos podem ser baixados e testados:

Sample Document
MVC Exemplo do ASP.NET Core 2.1 MVC SameSite cookie
Razor Páginas Exemplo de SameSite Razor do ASP.NET Core 2.1 cookie Pages

Alterações no comportamento do patch de dezembro

A alteração de comportamento específica para .NET Framework e .NET Core 2.1 é como a SameSite propriedade interpreta o None valor. Antes da correção, um valor de None significava "Não emitir o atributo de forma alguma", depois da correção, passou a significar "Emitir o atributo com um valor de None". Após o patch, um valor de SameSite(SameSiteMode)(-1) faz com que o atributo não seja emitido.

O valor padrão de SameSite para autenticação de formulários e cookies de estado de sessão foi alterado de None para Lax.

Uso da API com o SameSite

HttpContext.Response.Cookies.Append assume como padrão Unspecified, o que significa que nenhum atributo SameSite foi adicionado ao cookie e o cliente usará seu comportamento padrão (Lax para novos navegadores, Nenhum para os antigos). O código a seguir mostra como alterar o cookie valor SameSite para SameSiteMode.Lax:

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

Todos os componentes principais ASP.NET que emitem cookies substituem os padrões anteriores com configurações apropriadas para seus cenários. Os valores padrão anteriores substituídos não foram alterados.

Component cookie Default
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery OpçõesAntifalsificação.Cookie Strict
Cookie Autenticação CookiesAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

História e mudanças

O suporte ao SameSite foi implementado pela primeira vez no ASP.NET Core em 2.0 usando o padrão de rascunho de 2016. A norma de 2016 era opcional. ASP.NET Core optou por participar definindo vários cookies como Lax por padrão. Depois de encontrar vários problemas com a autenticação, a maioria do uso do SameSite foi desativada.

Os patches foram emitidos em novembro de 2019 para atualizar do padrão de 2016 para o padrão de 2019. O rascunho de 2019 da especificação SameSite:

  • Não é retrocompatível com o projeto de 2016. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.
  • Especifica que os cookies são tratados como SameSite=Lax por padrão.
  • Os cookies que afirmam explicitamente SameSite=None devem ser marcados como Secure para permitir a entrega entre sites. None é uma nova entrada para optar por não participar.
  • É suportado por patches emitidos para ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 tem suporte adicional ao SameSite.
  • Está programado para ser ativado pelo Chrome por padrão em fevereiro de 2020. Os navegadores começaram a migrar para esse padrão em 2019.

APIs afetadas pela mudança do padrão de rascunho SameSite de 2016 para o padrão de rascunho de 2019

Suporte a navegadores mais antigos

O padrão SameSite de 2016 determinou que valores desconhecidos devem ser tratados como SameSite=Strict valores. As aplicações acedidas a partir de navegadores mais antigos que suportam o padrão SameSite de 2016 podem deixar de funcionar quando recebem uma propriedade SameSite com um valor de None. Os aplicativos Web devem implementar a deteção de navegador se pretenderem oferecer suporte a navegadores mais antigos. ASP.NET Core não implementa a deteção do navegador porque User-Agents valores são altamente voláteis e mudam com frequência. Um ponto de extensão em Microsoft.AspNetCore.CookiePolicy permite integrar lógica específica de User-Agent.

No Startup.Configure, adicione o código que chama UseCookiePolicy antes de chamar UseAuthentication ou qualquer método que escreva 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();
    });
}

No Startup.ConfigureServices, adicione um código semelhante ao seguinte:

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

    }
}

No exemplo anterior, MyUserAgentDetectionLib.DisallowsSameSiteNone é uma biblioteca fornecida pelo usuário que deteta se o agente do usuário não suporta SameSite None:

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

O código a seguir mostra um método de exemplo DisallowsSameSiteNone :

Warning

O código a seguir é apenas para demonstração:

  • Não deve ser considerado completo.
  • Não é mantido ou apoiado.
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;
}

Testar aplicativos para problemas do SameSite

Os aplicativos que interagem com sites remotos, como por meio de login de terceiros, precisam:

Teste aplicativos Web usando uma versão de cliente que pode aceitar o novo comportamento SameSite. Chrome, Firefox e Chromium Edge têm novos sinalizadores de recursos de aceitação que podem ser usados para testes. Depois de o aplicativo aplicar os patches do SameSite, teste com versões mais antigas do cliente, especialmente o Safari. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.

Teste com o Chrome

O Chrome 78+ dá resultados enganosos porque tem uma atenuação temporária em vigor. A atenuação temporária do Chrome 78+ permite cookies com menos de dois minutos. O Chrome 76 ou 77 com os sinalizadores de teste apropriados ativados fornece resultados mais precisos. Para testar o novo comportamento SameSite, alterne chrome://flags/#same-site-by-default-cookies para Enabled. As versões mais antigas do Chrome (75 e inferiores) apresentam falhas com a nova None definição. Consulte Suporte a navegadores mais antigos neste documento.

A Google não disponibiliza versões mais antigas do chrome. Siga as instruções em Transferir o Chromium para testar versões mais antigas do Chrome. Não transfira o Chrome a partir de hiperligações fornecidas ao procurar por versões antigas do Chrome.

A partir da versão 80.0.3975.0Canary, a mitigação temporária Lax+POST pode ser desativada para fins de teste usando o novo sinalizador --enable-features=SameSiteDefaultChecksMethodRigorously para permitir o teste de locais e serviços no eventual estado final do recurso em que a mitigação foi removida. Para obter mais informações, consulte The Chromium Projects SameSite Updates

Teste com o Safari

O Safari 12 implementou estritamente o rascunho anterior e falha quando o novo valor None está num cookie arquivo. None é evitada usando o código de detecção de navegadores Suporte para navegadores mais antigos neste documento. Teste os logins ao estilo do sistema operativo baseados no Safari 12, Safari 13 e WebKit usando MSAL, ADAL ou qualquer biblioteca que estejas a utilizar. O problema depende da versão subjacente do sistema operacional. O OSX Mojave (10.14) e o iOS 12 são conhecidos por terem problemas de compatibilidade com o novo comportamento do SameSite. Atualizar o sistema operacional para OSX Catalina (10.15) ou iOS 13 corrige o problema. Atualmente, o Safari não tem um sinalizador de aceitação para testar o novo comportamento das especificações.

Teste com o Firefox

O suporte do Firefox para o novo padrão pode ser testado na versão 68+, ativando na página about:config com a bandeira de recurso network.cookie.sameSite.laxByDefault. Não houve relatos de problemas de compatibilidade com versões mais antigas do Firefox.

Teste com o navegador Edge

O Edge suporta o antigo padrão SameSite. A versão 44 do Edge não tem problemas de compatibilidade conhecidos com o novo padrão.

Teste com Edge (Chromium)

Os sinalizadores SameSite são definidos na edge://flags/#same-site-by-default-cookies página. Não foram detetados problemas de compatibilidade com o Edge Chromium.

Teste com Electron

As versões do Electron incluem versões mais antigas do Chromium. Por exemplo, a versão usada Electron pelo Teams é o Chromium 66, que exibe o comportamento mais antigo. Você deve realizar seus próprios testes de compatibilidade com a versão que o Electron seu produto utiliza. Consulte Suporte a navegadores mais antigos na seção a seguir.

Recursos adicionais

Sample Document
MVC Exemplo do ASP.NET Core 2.1 MVC SameSite cookie
Razor Páginas Exemplo de SameSite Razor do ASP.NET Core 2.1 cookie Pages