aspnet / Announcements

Subscribe to this repo to be notified about major changes in ASP.NET Core and Entity Framework Core
Other
1.66k stars 80 forks source link

Reacting to browser SameSite changes in 3.1.0-preview1, impacts OpenIdConnect #390

Open Tratcher opened 4 years ago

Tratcher commented 4 years ago

Reacting to browser SameSite changes in 3.1.0-preview1, impacts OpenIdConnect

Browsers like Chrome and Firefox are making breaking changes to their implementations of SameSite for cookies. These changes impact remote authentication scenarios like OpenIdConnect and WsFederation which must now opt out by sending SameSite=None. However, SameSite=None breaks on iOS 12 and some older versions of other browsers. The application will need to sniff these versions and omit SameSite.

For discussion on this issue see https://github.com/aspnet/AspNetCore/issues/14996.

Version introduced

3.1.0-preview1

Old behavior

SameSite is a 2016 draft standard extension to HTTP cookies intended to mitigate cross site request forgery (CSRF). This was originally designed as a feature the servers would opt into by adding the new parameters. ASP.NET Core 2.0 added initial support for SameSite.

New behavior

Google is now pushing a new draft standard that is not backwards compatible. It changes the default mode to Lax and adds a new entry None to opt out. Lax is OK for most application cookies but breaks cross site scenarios like OpenIdConnect and WsFederation login. Most OAuth logins are not affected due to differences in how the request flows. The new None parameter causes compatibility problems with clients that implemented the prior draft standard (e.g. iOS 12). Chrome plans to go live with their changes in Chrome 80 in February 2020.

ASP.NET Core 3.1 has been updated to implement the new SameSite behavior. This includes redefining the behavior of SameSiteMode.None to emit “SameSite=None” and adding a new value SameSiteMode.Unspecified to omit the SameSite attribute. All cookies APIs now default to Unspecified, though some components that use cookies set values more specific to their scenarios such as the OpenIdConnect correlation and nonce cookies.

For other recent changes in this area see the 3.0 announcement where most defaults were changed from Lax to None (but still using the prior standard).

Reason for change

Browser and spec changes as outlined above.

Recommended action

Applications that interact with remote sites such as through 3rd party login will need to test those scenarios on multiple browsers, as well as apply the CookiePolicy browser sniffing mitigation discussed below. See below for testing and browser sniffing instructions. How to test if you’re affected Test your web application using a client version that can opt-in to the new behavior. Chrome, Firefox, and Chromium Edge all have new opt-in feature flags that can be used for testing. You’ll also want to do compatibility testing with older client versions after you’ve applied the patches, especially Safari. See “Supporting older browsers” below.

Chrome: Chrome 78+ will give you misleading test results as it has a temporary mitigation in place, allowing cookies less than two minutes old. Chrome 76 or 77 with the appropriate test flags turned on will give you more accurate results. To test the new behavior toggle chrome://flags/#same-site-by-default-cookies to enabled. Older versions of Chrome (75 and below) are reported to fail with the new None setting. See “Supporting older browsers” below. Whilst Google does not make older chrome versions available you can download older versions of Chromium which will suffice for testing. Follow the instructions at https://www.chromium.org/getting-involved/download-chromium, don’t go downloading random assed installers from the internet that say they’re for older versions.
Chromium 76 Win64 Chromium 74 Win64

Safari: Safari 12 strictly implemented the prior draft and will fail if it sees the new None value in cookies. This must be avoided via the browser sniffing code shown below. Ensure you test Safari 12 and Safari 13 as well as WebKit based OS style logins using MSAL, ADAL or whatever library you are using. Note that the problem is dependent on the underlying OS version, OSX Mojave (10.14) and iOS 12 are known to have compatibility problems with the new behavior. Upgrading the OS to OSX Catalina (10.15) or iOS 13 fixes the problem. Safari does not currently have an opt-in flag for testing the new spec behavior.

Firefox: Firefox support for the new standard can be tested on version 68+ by opting in on the “about:config” page with the feature flag “network.cookie.sameSite.laxByDefault”. There have not been reports of compatibility issues with older versions of Firefox.

Edge: While Edge supports the old SameSite standard, as of version 44 it did not have any compatibility problems with the new standard.

Edge (Chromium): The feature flag is edge://flags/#same-site-by-default-cookies. No compatibility issues were observed when testing with Edge Chromium 78.

Electron: Versions of electron will include older versions of Chromium, for example the version of Electron used by Teams is Chromium 66 which exhibits the older behavior. You must perform your own compatibility testing with the version of Electron your product uses. See “Supporting older browsers” below.

Supporting older browsers: The 2016 SameSite standard mandated that unknown values must be treated as SameSite=Strict values, so any older browsers which support the original standard may break when they see a SameSite property with a value of None. Web applications must implement browser sniffing if they intend to support these old browsers. AspNetCore as a rule does not implement browser sniffing for you because User-Agents values are highly unstable and change on a weekly basis. What is available is an extension point in CookiePolicy allowing you to plug in User-Agent specific logic.

In Startup.cs add the following

private void CheckSameSite(HttpContext httpContext, CookieOptions options) 
{ 
    if (options.SameSite == SameSiteMode.None) 
    { 
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); 
        // TODO: Use your User Agent library of choice here. 
        if (/* UserAgent doesn’t support new behavior */) 
        { 
               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(); 
    // … 
}

Opt-out switches: There is a compat switch which enables you to temporarily opt-out of the new ASP.NET Core cookie behavior. Add a runtimeconfig.template.json file to your project containing:

{ 
  "configProperties": { 
    "Microsoft.AspNetCore.SuppressSameSiteNone": "true" 
  } 
} 

This switch will be removed in the next major version.

Other Versions: Related SameSite patches are forthcoming for ASP.NET Core 2.1, 2.2, 3.0, Microsoft.Owin 4.1, and System.Web (.NET 4.7.2+).

Category

ASP.NET

Affected APIs

SameSiteMode CookieOptions.SameSite CookieBuilder.SameSite CookiePolicyOptions.MinimumSameSitePolicy

Microsoft.Net.Http.Headers: SameSiteMode SetCookieHeaderValue.SameSite


Issue metadata

Tratcher commented 4 years ago

I've made a correction to the sample code above. It used to read:

private void CheckSameSite(HttpContext httpContext, CookieOptions options) 
{ 
    if (options.SameSite > SameSiteMode.Unspecified) 
    { 

But the corrected version is:

private void CheckSameSite(HttpContext httpContext, CookieOptions options) 
{ 
    if (options.SameSite == SameSiteMode.None) 
    { 
Tratcher commented 4 years ago

Patches

See https://devblogs.microsoft.com/dotnet/net-core-November-2019/ for information on the November 2.1.14, 2.2.8, and 3.0.1 patches that included these changes.

ASP.NET Core 2.1 or 2.2 on .NET Framework:

ASP.NET Core and System.Web (ASP.NET Classic) have independent implementations of SameSite. The SameSite KB patches for .NET Framework are not required if using ASP.NET Core. Nor does the System.Web SameSite minimum framework version requirement (.NET 4.7.2) apply to ASP.NET Core. ASP.NET Core on .NET requires updating nuget package dependencies to get the appropriate fixes.

To get the ASP.NET Core changes for .NET Framework ensure that you have a direct reference to the patched packages and versions (2.1.14 or 2.2.8).

<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.1.14" />
<PackageReference Include="Microsoft.AspNetCore.CookiePolicy" Version="2.1.14" />