Compartir a través de


Ejemplo de cookie SameSite para ASP.NET 4.7.2 C# MVC

.NET Framework 4.7 tiene compatibilidad integrada con el atributo SameSite, pero se adhiere al estándar original. El comportamiento revisado ha cambiado el significado de SameSite.None para que el atributo se emita con un valor de None, en lugar de no emitir ningún valor. Si no quiere emitir el valor, puede establecer la propiedad SameSite en una cookie en -1.

Escritura del atributo SameSite

A continuación se muestra un ejemplo de cómo escribir un atributo SameSite en una cookie;

// Create the cookie
HttpCookie sameSiteCookie = new HttpCookie("SameSiteSample");

// Set a value for the cookieSite none.
// Note this will also require you to be running on HTTPS
sameSiteCookie.Value = "sample";

// Set the secure flag, which Chrome's changes will require for Same
sameSiteCookie.Secure = true;

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

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

// Add the cookie to the response cookie collection
Response.Cookies.Add(sameSiteCookie);

Si está leyendo este contenido en un idioma que no es el inglés, díganos si le gustaría que los comentarios sobre el código estuviesen en escritos en su idioma. Puede hacerlo en este artículo de discusión de GitHub.

El atributo sameSite predeterminado para el estado de sesión se establece en el parámetro "cookieSameSite" de la configuración de sesión en web.config

<system.web>
  <sessionState cookieSameSite="None">     
  </sessionState>
</system.web>

Autenticación de MVC

La autenticación basada en cookies MVC de OWIN usa un administrador de cookies para habilitar el cambio de atributos de cookie. SameSiteCookieManager.vb es una implementación de esa clase que puede copiar en proyectos propios.

Debe asegurarse de que todos los componentes Microsoft.Owin estén actualizados a la versión 4.1.0 o posterior. Compruebe el archivo packages.config para asegurarse de que coincidan todos los números de versión, por ejemplo.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <!-- other packages -->
  <package id="Microsoft.Owin.Host.SystemWeb" version="4.1.0" targetFramework="net472" />
  <package id="Microsoft.Owin.Security" version="4.1.0" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.Cookies" version="4.1.0" targetFramework="net472" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net472" />
  <package id="Owin" version="1.0" targetFramework="net472" />
</packages>

Después, los componentes de autenticación se deben configurar para utilizar CookieManager en la clase de inicio;

public void Configuration(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        CookieSameSite = SameSiteMode.None,
        CookieHttpOnly = true,
        CookieSecure = CookieSecureOption.Always,
        CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
    });
}

Se debe establecer un administrador de cookies en cada componente que lo admita, incluidos CookieAuthentication y OpenIdConnectAuthentication.

SystemWebCookieManager se utiliza para evitar problemas conocidos con la integración de cookies de respuesta.

Ejecución del ejemplo

Si ejecuta el proyecto de ejemplo, cargue el depurador del explorador en la página inicial y úselo para ver la colección de cookies del sitio. Para ello, en Edge y Chrome, presione F12, seleccione la pestaña Application y haga clic en la dirección URL del sitio en la opción Cookies de la sección Storage.

Browser Debugger Cookie List

En la imagen anterior, puede ver que la cookie creada por el ejemplo al hacer clic en el botón "Crear cookies" tiene un valor de atributo SameSite de Lax, que coincide con el valor establecido en el código de ejemplo.

Intercepción de cookies no controladas

En .NET 4.5.2 se introdujo un nuevo evento para interceptar la escritura de encabezados, Response.AddOnSendingHeaders. Esto se puede utilizar para interceptar las cookies antes de que se devuelvan a la máquina cliente. En el ejemplo, se establece el evento en un método estático que comprueba si el explorador admite los nuevos cambios en sameSite y, si no es así, cambia las cookies para que no emitan el atributo si se ha establecido el nuevo valor None.

Vea global.asax para obtener un ejemplo de enlace del evento y SameSiteCookieRewriter.cs para obtener un ejemplo de cómo controlar el evento y ajustar el atributo de cookie sameSite que puede copiar en el código.

public static void FilterSameSiteNoneForIncompatibleUserAgents(object sender)
{
    HttpApplication application = sender as HttpApplication;
    if (application != null)
    {
        var userAgent = application.Context.Request.UserAgent;
        if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
        {
            HttpContext.Current.Response.AddOnSendingHeaders(context =>
            {
                var cookies = context.Response.Cookies;
                for (var i = 0; i < cookies.Count; i++)
                {
                    var cookie = cookies[i];
                    if (cookie.SameSite == SameSiteMode.None)
                    {
                        cookie.SameSite = (SameSiteMode)(-1); // Unspecified
                    }
                }
            });
        }
    }
}

Puede cambiar el comportamiento de cookies con nombre específico de la misma manera; en el ejemplo siguiente se ajusta la cookie de autenticación predeterminada de Lax a None en exploradores que admiten el valor None, o se quita el atributo sameSite de los exploradores que no admiten None.

public static void AdjustSpecificCookieSettings()
{
    HttpContext.Current.Response.AddOnSendingHeaders(context =>
    {
        var cookies = context.Response.Cookies;
        for (var i = 0; i < cookies.Count; i++)
        {
            var cookie = cookies[i]; 
            // Forms auth: ".ASPXAUTH"
            // Session: "ASP.NET_SessionId"
            if (string.Equals(".ASPXAUTH", cookie.Name, StringComparison.Ordinal))
            { 
                if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
                {
                    cookie.SameSite = -1;
                }
                else
                {
                    cookie.SameSite = SameSiteMode.None;
                }
                cookie.Secure = true;
            }
        }
    });
}

Más información

Actualizaciones de Chrome

Documentación de SameSite de OWIN

Documentación de ASP.NET

Revisiones de SameSite de .NET