Upcoming SameSite Cookie Changes in ASP.NET and ASP.NET Core

SameSite is the 2016 HTTP cookie extension designed to prevent cross-site request forgery (CSRF). Initially, its design was an additional feature that can be used by adding a new SameSite property to cookies. It had two meanings, Lax and Strict.



When setting the Lax value, it is understood that cookies should be sent when surfing one site or via GET surfing to your site from other sites. The Strict value limited cookies to requests coming from only one site. The lack of setting any property does not impose any restrictions on how cookies can work in requests. OpenIdConnect authentication operations (such as logging in, logging out) and other functions that send POST requests from an external site to the site requesting the operation can use cookies to correlate and / or protect CSRF. These operations would have to reject SameSite without setting a property at all to ensure that these cookies are sent during their specialized request flows.



Google is currently updating the standard and introducing the proposed changes in a future version of Chrome. The change adds the same SameSite “None” value and changes the default behavior to “Lax”. This breaks OpenIdConnect logins and possibly other features that your website can build on. These features will need to use cookies whose SameSite property is set to None.



However, browsers that adhere to the original standard and are not aware of the new value behave differently than browsers that use the new standard. This means that your .NET website will now need to add user agent sniffing to decide whether to send a new None value or not to send an attribute at all.







.NET will receive updates to change the behavior of the SameSite attribute in .NET 4.7.2 and .NET Core 2.1 and later to adapt to Google’s introduction of the new value. Updates for the .NET Framework will be available on November 19 as an additional update through Microsoft Update and WSUS if you use the Check for Updates feature. On December 10, the update will become publicly available and will appear in the Microsoft Update Center. .NET Core updates will be available in November with the release of .NET Core 3.1, starting with Preview 1.



.NET Core 3.1 will contain an updated enum definition , SameSite.Unspecified, which will not set the SameSite property.



OpenIdConnect middleware for Microsoft.Owin v4.1 and .NET Core will be updated simultaneously with updates to the .NET Framework and .NET, however, we cannot add user agent sniffing code to the framework, this must be implemented in the code of your site. The implementation of agent sniffing will depend on which version of ASP.NET or ASP.NET Core you are using and which browsers you want to support.



For ASP.NET 4.7.2 with Microsoft.Owin 4.1.0 agent sniffing can be implemented using ICookieManager ;



public class SameSiteCookieManager : ICookieManager { private readonly ICookieManager _innerManager; public SameSiteCookieManager() : this(new CookieManager()) { } public SameSiteCookieManager(ICookieManager innerManager) { _innerManager = innerManager; } public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options) { CheckSameSite(context, options); _innerManager.AppendResponseCookie(context, key, value, options); } public void DeleteCookie(IOwinContext context, string key, CookieOptions options) { CheckSameSite(context, options); _innerManager.DeleteCookie(context, key, options); } public string GetRequestCookie(IOwinContext context, string key) { return _innerManager.GetRequestCookie(context, key); } private void CheckSameSite(IOwinContext context, CookieOptions options) { if (DisallowsSameSiteNone(context) && options.SameSite == SameSiteMode.None) { options.SameSite = null; } } public static bool DisallowsSameSiteNone(IOwinContext context) { // TODO:    User Agent . var userAgent = context.Request.Headers["User-Agent"]; return userAgent.Contains("BrokenUserAgent") || userAgent.Contains("BrokenUserAgent2") } }
      
      





And then configure the OpenIdConnect settings to use the new CookieManager;



 app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { // …    … CookieManager = new SameSiteCookieManager(new SystemWebCookieManager()) });
      
      





For the SystemWebCookieManager to work properly, you will need to install the fixed SameSite .NET 4.7.2 or later.



For ASP.NET Core, you must install the patches and then inject the agent sniffing code into the cookie policy . For versions prior to 3.1, replace SameSiteMode.Unspecified with (SameSiteMode) (- 1).



 private void CheckSameSite(HttpContext httpContext, CookieOptions options) { if (options.SameSite > SameSiteMode.Unspecified) { var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); // TODO:    User Agent . if (/* UserAgent doesn't support new behavior */) { //  .NET Core < 3.1  SameSite = -1 options.SameSite = SameSiteMode.Unspecified; } } } 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); }); } public void Configure(IApplicationBuilder app) { app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies. app.UseAuthentication(); // … }
      
      





When testing with the Azure Active Directory team, we found that the following checks work for all common user agents that, according to Azure Active Directory, do not understand the new value.



 public static bool DisallowsSameSiteNone(string userAgent) {    //      iOS.   :    // - Safari  iOS 12  iPhone, iPod Touch, iPad    // - WkWebview  iOS 12  iPhone, iPod Touch, iPad    // - Chrome  iOS 12  iPhone, iPod Touch, iPad    if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12"))    {        return true;    }    //     Mac OS X.   :    // - Safari  Mac OS X.    //  :    // - Chrome  Mac OS X    //        Mac OS.    if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && userAgent.Contains("Version/") && userAgent.Contains("Safari"))    {        return true;    }    //    Chrome 50-69,      SameSite=None.    if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))    {        return true;    }    return false; }
      
      





This list of browsers is by no means something you can fully rely on, and you should check that the regular browsers and other user agents supported by your system behave properly after the update is installed.



Chrome 80 is due to transition to new behavior in February or March 2020. If you want to check out the new behavior, older versions of Chromium are available for download .



If you cannot upgrade your framework version by the time Chrome enables the new behavior in early 2020, you may be able to change the OpenIdConnect stream to a Code stream, and not to the stream used by ASP.NET and ASP.NET Core. But this should be seen as a temporary measure.





We strongly recommend that you download the updated versions of the .NET Framework and .NET Core when they become available in November and start planning for the update before changes are made to Chrome.



All Articles