About Samesite cookies
First of all, you can learn about SameSite cookies at https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies and at https://web.dev/samesite-cookies-explained/.
The .NET team had a blog post to explain why recent changes in the specification can cause problems:
SameSite is a 2016 extension to HTTP cookies intended to mitigate cross site request forgery (CSRF). The original design was an opt-in feature which could be used by adding a new SameSite property to cookies. It had two values, Lax and Strict. Setting the value to Lax indicated the cookie should be sent on navigation within the same site, or through GET navigation to your site from other sites. A value of Strict limited the cookie to requests which only originated from the same site. Not setting the property at all placed no restrictions on how the cookie flowed in requests. OpenIdConnect authentication operations (e.g. login, logout), and other features that send POST requests from an external site to the site requesting the operation, can use cookies for correlation and/or CSRF protection. These operations would need to opt-out of SameSite, by not setting the property at all, to ensure these cookies will be sent during their specialized request flows.
Google is now updating the standard and implementing their proposed changes in an upcoming version of Chrome. The change adds a new SameSite value, "None", and changes the default behavior to "Lax". This breaks OpenIdConnect logins, and potentially other features your web site may rely on, these features will have to use cookies whose SameSite property is set to a value of "None". However browsers which adhere to the original standard and are unaware of the new value have a different behavior to browsers which use the new standard as the SameSite standard states that if a browser sees a value for SameSite it does not understand it should treat that value as "Strict". This means your .NET website will now have to add user agent sniffing to decide whether you send the new None value, or not send the attribute at all.
TL;DR
Before Chrome 80 is released (and other browsers before they turn the new SameSite behavior on):
- If your servers have not installed the latest SameSite updates for .NET, you are good.
- If your servers have installed the latest SameSite updates for .NET:
- If you need to support old browsers, you can use the approach in the "Workaround" section below.
- If you do not need to support old browsers, you can either check out the "Workaround - not support old browsers" section or the "Final solution" section.
After Chrome 80 is released (and other browsers when they turn the new SameSite behavior on):
- You need to install the latest SameSite updates for .NET.
- If you need to support old browsers, you can use the approach in the "Workaround" section below.
- If you do not need to support old browsers, please check out the "Final solution" section.
Problems that the new SameSite specification will cause to Safewhere's products
First of all, please note that the upcoming problems will only happen when at least one of the following happens:
- You install a latest .NET patch.
- Or you are using a Chrome build/configuration that enables the new SameSite behaviors.
SAML 2.0/WSFed/OAuth/OIDC logins work as follows:
- An SP sends a request to Safewhere Identify. Identify - as an Asp.Net application - creates a new session and writes the session id to a cookie named identify_sessionid.
- The user selects an upstream IdP to use. It may be a SAML 2.0, WSFed, or OAuth/OIDC provider. Identify will send an authentication request to the IdP. If an OAuth/OIDC IdP is used, Identify will also create a correlation cookie.
- The user finishes logging in on the IdP side and the IdP returns a response to Identify by using a mechanism called "POST-based-redirect" which triggers SameSite protection.
The same problem can happen when a service provider or identity provider does POST based redirects to Identify for AuthnRequest or LogoutRequest/LogoutResponse. Besides, your own service provider may have the same issue.
All cookies that are affected by the SameSite changes are:
- identify_sessionid
- identify_auth
- correlation
- AuthenticationConnectionId
- participants cookies
Changes that are/were happening
Google Chrome
Chrome is making a number of changes. The most important timestamp is that from Chrome 80 stable, which will be released by February 4, 2020:
* Cookies without a SameSite attribute will be treated as SameSite=Lax.
* Cookies with SameSite=None must also specify Secure.
Chrome implements these behaviors as of version 80. Firefox has them available to test and will be making them default behaviors in the future. Edge also plans to change its default behaviors.
Credit: https://web.dev/samesite-cookies-explained/
This means that by the time Chrome 80 is released, the new default behavior may cause big problems to many web applications.
More details from the Chromium team: https://blog.chromium.org/2019/10/developers-get-ready-for-new.html
.NET framework
The .NET team released a bunch of updates to support the new specification:
ASP.NET now emits a SameSite cookie header when HttpCookie.SameSite value is "None" to accommodate upcoming changes to SameSite cookie handling in Chrome. As part of this change, FormsAuth and SessionState cookies are also issued with SameSite = 'Lax' instead of the previous default of 'None', though these values can be overridden in web.config.
For more information, refer to: https://docs.microsoft.com/en-us/aspnet/samesite/system-web-samesite.
What is the immediate problem
The update from Microsoft is supposed to be optional. The ideal scenario is:
- We install the update on dev machines.
- We implement necessary code and test to make sure the new SameSite spec is supported by our products on all browsers. In addition, we will document workaround, if there is, for those who can't update yet.
- We roll out updates for our products to you to test it together with the new .NET update on your servers before Chrome 80 is released.
However, we got reported that some of our customers' servers have got that optional update installed. The consequence is that SAML 2.0 logins and OpenId Connection logins might stop working.
Workaround
This workaround applies if you want to support old browsers that implemented SameSite wrong. Please note that this workaround can apply to the Identify version 5.1.1++ but it will stop working on Chrome 80 as well as on future releases of other browsers. You will need to install our software updates before that timeline or check the next workaround.
If you have installed the latest .NET patch on your server, you can opt-out of the new behavior as follows:
Step 1: use the following command to decrypt the web.config file of your Identify instance:
aspnet_regiis.exe -pdf "system.web/sessionState" "C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\runtime"
Step 2: add the sameSite attribute to the system.web/httpCookies
section. The httpOnlyCookies attribute is optional but we recommend that you set it to true to prevent JavaScript code from accessing your cookies.
<httpCookies httpOnlyCookies="true" requireSSL="true" sameSite="None"/>
Step 3: add the cookieSameSite attribute to the sessionState
section:
<sessionState ... cookieSameSite="None" />
For example:
<sessionState mode="InProc" cookieName="Identify_SessionId" timeout="60" cookieSameSite="None" />
Step 4: add the cookieSameSite attribute to the authentication/forms
section:
<authentication mode="None">
<forms timeout="60" requireSSL="true" name="identify_auth" cookieSameSite="None" />
</authentication>
Step 5: add the key below to the appSettings section:
<add key="aspnet:SuppressSameSiteNone" value="true"/>
Step 6: save the web.config file.
Step 7: encrypt your web.config:
aspnet_regiis.exe -pef "system.web/sessionState" "C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\runtime"
Workaround - not support old browsers
You will not need to update your Safewhere Identify deployment if you do not need to support users who are using the following browser clients: https://www.chromium.org/updates/same-site/incompatible-clients
Step 1: use the following command to decrypt the web.config file of your Identify instance:
aspnet_regiis.exe -pdf "system.web/sessionState" "C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\runtime"
Step 2: add the sameSite attribute to the system.web/httpCookies
section. The httpOnlyCookies attribute is optional but we recommend that you set it to true to prevent JavaScript code from accessing your cookies.
<httpCookies httpOnlyCookies="true" requireSSL="true" sameSite="None"/>
Step 3: add the cookieSameSite attribute to the sessionState
section:
<sessionState ... cookieSameSite="None" />
Step 4: add the cookieSameSite attribute to the authentication/forms
section:
<authentication mode="None">
<forms timeout="60" requireSSL="true" name="identify_auth" cookieSameSite="None" />
</authentication>
Step 5: save the web.config file.
Step 6: encrypt your web.config:
aspnet_regiis.exe -pef "system.web/sessionState" "C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\runtime"
Final solution
NOTE
Unlike the workarounds above which either does not support old browsers or will stop working when Chrome 80 is released. This solution can virtually work in all situations.
Because Safewhere Identify needs to use its cookies in the POST-based-redirect manner, those cookies must use SameSite=None. The problem now is to deal with old browsers that do not support the None option.
According to guidances from Microsoft and Google:
- https://web.dev/samesite-cookie-recipes/
- https://docs.microsoft.com/en-us/aspnet/samesite/system-web-samesite
- https://auth0.com/blog/browser-behavior-changes-what-developers-need-to-know/
the two common solutions are:
- Use browser agent sniffing.
- Use double cookies.
Although both solutions have pros and cons, we opted for the browser agent sniffing one because the double cookies approach will double cookie's size which may end up with the exceeding cookie size limit problem.
Safewhere Identify version 5.6 will ship with support for the new SameSite behavior as well as support for old browsers by default. If you are using a previous version and want to support old browsers, you will need to deploy the patch, which is a dll named Safewhere.Extensions.SameSite, into the Runtime\Bin folder of your Identify instance.
The Safewhere.Extensions.SameSite dll has an Asp.Net MVC's global filter that uses browser agent sniffing technique to detect and set the SameSite flag to empty if the browser does not support the None option. Implementing the path in a separate dll also means that we can release bug fixes or improvements for it easily.
How to apply the patch
From Identify version 5.1.1.4514 to latest version 5.5
First of all, you need to install .NET 4.7.2 or 4.8 on your server as well as all the latest patches.
Step 1: download the latest extension.
Step 2: deploy the dll to C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\bin
Step 3: use the following command to decrypt the web.config file of your Identify instance:
aspnet_regiis.exe -pdf "system.web/sessionState" "C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\runtime"
Step 4: open to edit the web.config file
Step 5: update the AppStartup setting under the appSettings section as follows:
<add key="owin:AppStartup" value="Safewhere.IdentityProvider.OAuth2.Startup, Safewhere.IdentityProvider.OAuth2" />
To
<add key = "owin:AppStartup" value="Safewhere.Extensions.SameSite.RuntimeStartup, Safewhere.Extensions.SameSite" />
Step 6: add the sameSite attribute to the system.web/httpCookies
section. The httpOnlyCookies attribute is optional but we recommend that you set it to true to prevent JavaScript code from accessing your cookies.
<httpCookies httpOnlyCookies="true" requireSSL="true" sameSite="None"/>
Step 7: add the cookieSameSite attribute to the sessionState
section:
<sessionState ... cookieSameSite="None" />
Step 8: add the cookieSameSite attribute to the authentication/forms
section:
<authentication mode="None">
<forms timeout="60" requireSSL="true" name="identify_auth" cookieSameSite="None" />
</authentication>
Step 9: save your web.config file.
Step 10: encrypt your web.config:
aspnet_regiis.exe -pef "system.web/sessionState" "C:\Program Files\Safewhere\Identify\Tenants\#yourTenantT1\runtime"
For Identify 5.6 and later
The patch is shipped with Identify 5.6 out of the box. You will not need to make any manual change to your Identify instances.
Service providers
Saml 2.0 for WIF component
Note: SAML 2.0 for WIF is a component and each application that uses it is different. The workarounds that we are proposing here are technical tips. They are not universal solutions that you should use as-is without proper consideration.
If you do not need to support old browsers and assuming that your application is using all the standard Asp.Net and WIF's cookies, you can follow the next steps to enable SameSite support:
Step 1: install .NET 4.7.2 or 4.8 on your server as well as all the latest patches.
Step 2: add the sameSite attribute to the system.web/httpCookies
section (and add the section to your web.config if it is not there. If the section does not exist in your web.config, it will mean that you are using its default settings). The httpOnlyCookies attribute is optional but we recommend that you set it to true to prevent JavaScript code from accessing your cookies.
<httpCookies httpOnlyCookies="true" requireSSL="true" sameSite="None"/>
Please note that using sameSite="None" here will turn all cookies of your application to None which can be a security risk. The reason that you need to set this one is to let the FedAuth cookies set to sameSite="None". An alternative is to make a custom Cookie Handler.
Step 3: add the cookieSameSite attribute to the sessionState
section:
<sessionState ... cookieSameSite="None" />
Step 4: add the cookieSameSite attribute to the authentication/forms
section:
<authentication mode="Forms">
<forms cookieless="UseCookies" loginUrl="/login.ashx" name="demoserviceprovider" cookieSameSite="None" />
</authentication>
If you want to support old browsers, you will need to do browser sniffing. You can find sample code for doing that at https://github.com/Safewhere/Safewhere-Identify-samples/tree/master/SameSite-Cookies.