Trabalhe com cookies SameSite no ASP.NET Core

De Rick Anderson

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

  • Cookies sem o cabeçalho SameSite são tratados como SameSite=Lax por padrão.
  • SameSite=None deve ser usado para permitir o uso de cookie entre sites.
  • Cookies que declaram SameSite=None também devem ser marcados como Secure.
  • Os aplicativos que usam <iframe> podem enfrentar problemas com cookies sameSite=Lax ou sameSite=Strict porque <iframe> é tratado 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 configuração SameSite=Lax funciona para a maioria dos cookies dos aplicativos. Algumas formas de autenticação, como OpenID Connect (OIDC) e WS-Federation, são padrão para redirecionamentos baseados em POST. Os redirecionamentos baseados em POST disparam as proteções do navegador SameSite, portanto, SameSite está desabilitado para esses componentes. A maioria dos logons do OAuth não é afetada 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

A Identity do ASP.NET Core não é substancialmente afetada pelos cookies SameSite, exceto por cenários avançados, como integração de IFrames ou OpenIdConnect.

Ao usar Identity, não adicione nenhum provedor cookie ou chame services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme), o Identity cuida disso.

Código de exemplo de teste SameSite

O seguinte exemplo pode ser baixado e testado:

Amostra Documento
Razor Pages do ASP.NET Core Amostra de Razor Pages SameSite cookie do ASP.NET Core 3.1

Suporte do .NET Core para o atributo SameSite

O .NET Core dá suporte ao padrão de rascunho de 2019 para SameSite. Os desenvolvedores podem controlar programaticamente o valor do atributo SameSite usando a propriedade HttpCookie.SameSite. Definir a propriedade SameSite como Strict, Lax ou None resulta na gravação desses valores na rede com o cookie. Definir como SameSiteMode.Unspecified indica que nenhum SameSite 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 de API com SameSite

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

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

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

Componente cookie Padrão
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Autenticação 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 e 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 tem o padrão Unspecified. Alguns componentes que usam cookies definem valores mais específicos para seus cenários. Consulte a tabela acima para exemplos.

No ASP.NET Core 3.0 e 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 estes cookies:

Histórico e alterações

O suporte ao SameSite foi implementado pela primeira vez em ASP.NET Core em 2.0 usando o padrão de rascunho de 2016. O padrão de 2016 era opcional. ASP.NET Core aceitou ao definir 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 desabilitada.

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

  • Não é compatível com versões anteriores com o rascunho de 2016. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.
  • Especifica que cookies são tratados como SameSite=Lax por padrão.
  • Especifica cookies que declaram SameSite=None explicitamente para habilitar a entrega entre sites deve ser marcado como Secure. None é uma nova entrada a ser recusada.
  • Há suporte para patches emitidos para ASP.NET Core 2.1, 2.2 e 3.0. ASP.NET Core 3.1 e posterior tem suporte adicional ao SameSite.
  • Está programado para ser habilitado pelo Chrome por padrão em fevereiro de 2020. Os navegadores começaram a mudar para esse padrão em 2019.

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

Suporte a navegadores mais antigos

O padrão do SameSite de 2016 determina que valores desconhecidos sejam tratados como valores SameSite=Strict. Os aplicativos acessados de navegadores mais antigos que dão suporte ao padrão SameSite de 2016 podem ser interrompidos quando recebem uma propriedade SameSite com um valor de None. Os aplicativos da Web devem implementar a detecção de navegador se pretenderem oferecer suporte a navegadores mais antigos. ASP.NET Core não implementa a detecção de navegador porque os valores de User-Agents são altamente voláteis e mudam com frequência. Um ponto de extensão no Microsoft.AspNetCore.CookiePolicy permite conectar User-Agent lógica específica.

No Program.cs, adicione o código que chama UseCookiePolicy antes de chamar UseAuthentication ou qualquer método que grave 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 detecta se o agente do usuário não dá suporte ao None do SameSite:

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

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

Aviso

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

  • Não deve ser considerado completo.
  • Ele não é mantido ou suportado.
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 logon de terceiros, precisam:

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

Testar com o Chrome

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

O Google não disponibiliza versões mais antigas do Chrome. Siga as instruções em Baixar Chromium para testar versões mais antigas do Chrome. Não baixe o Chrome de links fornecidos pesquisando versões mais antigas do Chrome.

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

Testar com o Safari

O Safari 12 implementou estritamente o rascunho anterior e falhará quando o novo valor None estiver em um cookie. None é evitado por meio do código de detecção do navegador Suporte a navegadores mais antigos neste documento. Teste os logons de estilo do sistema operacional baseados em Safari 12, Safari 13 e WebKit usando MSAL, ADAL ou qualquer biblioteca que você esteja usando. O problema depende da versão subjacente do sistema operacional. Sabe-se que o OSX Mojave (10.14) e o iOS 12 têm problemas de compatibilidade com o novo comportamento do SameSite. A atualização do SO para o OSX Catalina (10.15) ou iOS 13 corrige o problema. No momento, o Safari não tem um sinalizador de aceitação para testar o novo comportamento de especificação.

Testar com o Firefox

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

Testar com o navegador Edge

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

Testar com o Edge (Chromium)

Os sinalizadores SameSite são definidos na página edge://flags/#same-site-by-default-cookies. Nenhum problema de compatibilidade foi descoberto com o Edge Chromium.

Testar com Electron

As versões do Electron incluem versões mais antigas do Chromium. Por exemplo, a versão do Electron usada pelo Microsoft Teams é a Chromium 66, que exibe o comportamento mais antigo. Você precisa executar seu próprio teste de compatibilidade com a versão do Electron que o seu produto usa. Consulte Suporte a navegadores mais antigos na seção a seguir.

Recursos adicionais

Amostra Documento
Razor Pages do ASP.NET Core Amostra de Razor Pages SameSite cookie do ASP.NET Core 3.1

O seguinte exemplo pode ser baixado e testado:

Amostra Documento
Razor Pages do ASP.NET Core Amostra de Razor Pages SameSite cookie do ASP.NET Core 3.1

Suporte do .NET Core para o atributo SameSite

O .NET Core 3.1 e posterior dá suporte ao padrão de rascunho de 2019 para o SameSite. Os desenvolvedores podem controlar programaticamente o valor do atributo SameSite usando a propriedade HttpCookie.SameSite. Definir a propriedade SameSite como Strict, Lax ou None resulta na gravação desses valores na rede com o cookie. Defini-lo como igual a (SameSiteMode)(-1) indica que nenhum atributo SameSite deve ser incluído na rede 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.
    // 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 e posterior dá suporte aos valores SameSite atualizados e adiciona um valor de enumeração extra, SameSiteMode.Unspecified à enumeração SameSiteMode. Esse novo valor indica que nenhum SameSite deve ser enviado com o cookie.

Uso de API com SameSite

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

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

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

Componente cookie Padrão
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Autenticação 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 e 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 tem o padrão Unspecified. Alguns componentes que usam cookies definem valores mais específicos para seus cenários. Consulte a tabela acima para exemplos.

No ASP.NET Core 3.0 e 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 estes cookies:

Histórico e alterações

O suporte ao SameSite foi implementado pela primeira vez em ASP.NET Core em 2.0 usando o padrão de rascunho de 2016. O padrão de 2016 era opcional. ASP.NET Core aceitou ao definir 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 desabilitada.

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

  • Não é compatível com versões anteriores com o rascunho de 2016. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.
  • Especifica que cookies são tratados como SameSite=Lax por padrão.
  • Especifica cookies que declaram SameSite=None explicitamente para habilitar a entrega entre sites deve ser marcado como Secure. None é uma nova entrada a ser recusada.
  • Há suporte para 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 habilitado pelo Chrome por padrão em fevereiro de 2020. Os navegadores começaram a mudar para esse padrão em 2019.

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

Suporte a navegadores mais antigos

O padrão do SameSite de 2016 determina que valores desconhecidos sejam tratados como valores SameSite=Strict. Os aplicativos acessados de navegadores mais antigos que dão suporte ao padrão SameSite de 2016 podem ser interrompidos quando recebem uma propriedade SameSite com um valor de None. Os aplicativos da Web devem implementar a detecção de navegador se pretenderem oferecer suporte a navegadores mais antigos. ASP.NET Core não implementa a detecção de navegador porque os valores de User-Agents são altamente voláteis e mudam com frequência. Um ponto de extensão no Microsoft.AspNetCore.CookiePolicy permite conectar User-Agent lógica específica.

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

Em 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 detecta se o agente do usuário não dá suporte ao None do SameSite:

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

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

Aviso

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

  • Não deve ser considerado completo.
  • Ele não é mantido ou suportado.
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 logon de terceiros, precisam:

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

Testar com o Chrome

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

O Google não disponibiliza versões mais antigas do Chrome. Siga as instruções em Baixar Chromium para testar versões mais antigas do Chrome. Não baixe o Chrome de links fornecidos pesquisando versões mais antigas do Chrome.

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

Testar com o Safari

O Safari 12 implementou estritamente o rascunho anterior e falhará quando o novo valor None estiver em um cookie. None é evitado por meio do código de detecção do navegador Suporte a navegadores mais antigos neste documento. Teste os logons de estilo do sistema operacional baseados em Safari 12, Safari 13 e WebKit usando MSAL, ADAL ou qualquer biblioteca que você esteja usando. O problema depende da versão subjacente do sistema operacional. Sabe-se que o OSX Mojave (10.14) e o iOS 12 têm problemas de compatibilidade com o novo comportamento do SameSite. A atualização do SO para o OSX Catalina (10.15) ou iOS 13 corrige o problema. No momento, o Safari não tem um sinalizador de aceitação para testar o novo comportamento de especificação.

Testar com o Firefox

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

Testar com o navegador Edge

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

Testar com o Edge (Chromium)

Os sinalizadores SameSite são definidos na página edge://flags/#same-site-by-default-cookies. Nenhum problema de compatibilidade foi descoberto com o Edge Chromium.

Testar com Electron

As versões do Electron incluem versões mais antigas do Chromium. Por exemplo, a versão do Electron usada pelo Microsoft Teams é a Chromium 66, que exibe o comportamento mais antigo. Você precisa executar seu próprio teste de compatibilidade com a versão do Electron que o seu produto usa. Consulte Suporte a navegadores mais antigos na seção a seguir.

Recursos adicionais

Amostra Documento
Razor Pages do ASP.NET Core Amostra de Razor Pages SameSite cookie do ASP.NET Core 3.1

Os seguintes exemplos podem ser baixados e testados:

Amostra Documento
MVC do .NET Core Amostra de MVC do SameSite cookie do ASP.NET Core 2.1
Razor Pages do ASP.NET Core Amostra de Razor Pages SameSite cookie do ASP.NET Core 2.1

Alterações de comportamento de patch de dezembro

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

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

Uso de API com SameSite

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

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

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

Componente cookie Padrão
CookieBuilder SameSite Unspecified
Session SessionOptions.Cookie Lax
CookieTempDataProvider CookieTempDataProviderOptions.Cookie Lax
IAntiforgery AntiforgeryOptions.Cookie Strict
Cookie Autenticação CookieAuthenticationOptions.Cookie Lax
AddTwitter TwitterOptions.StateCookie Lax
RemoteAuthenticationHandler<TOptions> RemoteAuthenticationOptions.CorrelationCookie None
AddOpenIdConnect OpenIdConnectOptions.NonceCookie None
HttpContext.Response.Cookies.Append CookieOptions Unspecified

Histórico e alterações

O suporte ao SameSite foi implementado pela primeira vez em ASP.NET Core em 2.0 usando o padrão de rascunho de 2016. O padrão de 2016 era opcional. ASP.NET Core aceitou ao definir 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 desabilitada.

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

  • Não é compatível com versões anteriores com o rascunho de 2016. Para obter mais informações, consulte Suporte a navegadores mais antigos neste documento.
  • Especifica que cookies são tratados como SameSite=Lax por padrão.
  • Especifica cookies que declaram SameSite=None explicitamente para habilitar a entrega entre sites deve ser marcado como Secure. None é uma nova entrada a ser recusada.
  • Há suporte para 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 habilitado pelo Chrome por padrão em fevereiro de 2020. Os navegadores começaram a mudar para esse padrão em 2019.

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

Suporte a navegadores mais antigos

O padrão do SameSite de 2016 determina que valores desconhecidos sejam tratados como valores SameSite=Strict. Os aplicativos acessados de navegadores mais antigos que dão suporte ao padrão SameSite de 2016 podem ser interrompidos quando recebem uma propriedade SameSite com um valor de None. Os aplicativos da Web devem implementar a detecção de navegador se pretenderem oferecer suporte a navegadores mais antigos. ASP.NET Core não implementa a detecção de navegador porque os valores de User-Agents são altamente voláteis e mudam com frequência. Um ponto de extensão no Microsoft.AspNetCore.CookiePolicy permite conectar User-Agent lógica específica.

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

Em 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 detecta se o agente do usuário não dá suporte ao None do SameSite:

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

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

Aviso

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

  • Não deve ser considerado completo.
  • Ele não é mantido ou suportado.
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 logon de terceiros, precisam:

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

Testar com o Chrome

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

O Google não disponibiliza versões mais antigas do Chrome. Siga as instruções em Baixar Chromium para testar versões mais antigas do Chrome. Não baixe o Chrome de links fornecidos pesquisando versões mais antigas do Chrome.

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

Testar com o Safari

O Safari 12 implementou estritamente o rascunho anterior e falhará quando o novo valor None estiver em um cookie. None é evitado por meio do código de detecção do navegador Suporte a navegadores mais antigos neste documento. Teste os logons de estilo do sistema operacional baseados em Safari 12, Safari 13 e WebKit usando MSAL, ADAL ou qualquer biblioteca que você esteja usando. O problema depende da versão subjacente do sistema operacional. Sabe-se que o OSX Mojave (10.14) e o iOS 12 têm problemas de compatibilidade com o novo comportamento do SameSite. A atualização do SO para o OSX Catalina (10.15) ou iOS 13 corrige o problema. No momento, o Safari não tem um sinalizador de aceitação para testar o novo comportamento de especificação.

Testar com o Firefox

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

Testar com o navegador Edge

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

Testar com o Edge (Chromium)

Os sinalizadores SameSite são definidos na página edge://flags/#same-site-by-default-cookies. Nenhum problema de compatibilidade foi descoberto com o Edge Chromium.

Testar com Electron

As versões do Electron incluem versões mais antigas do Chromium. Por exemplo, a versão do Electron usada pelo Microsoft Teams é a Chromium 66, que exibe o comportamento mais antigo. Você precisa executar seu próprio teste de compatibilidade com a versão do Electron que o seu produto usa. Consulte Suporte a navegadores mais antigos na seção a seguir.

Recursos adicionais

Amostra Documento
MVC do .NET Core Amostra de MVC do SameSite cookie do ASP.NET Core 2.1
Razor Pages do ASP.NET Core Amostra de Razor Pages SameSite cookie do ASP.NET Core 2.1