Have you ever had a problem with SameSite cookies using IdentityServer?

Have you ever had a problem with SameSite cookies using IdentityServer?

If you use separate domains for your Web application and authentication server, this change in Chrome is likely to disrupt the session experience of some users

最后更新 4/28/2022 6:47 AM
Sebastian Gingter
预计阅读 16 分钟
分类
.NET
标签
.NET C# authentication homologous

Original author: Sebastian Gingter

Original link: https://www.example.com

Translator: The wolf at the end of the desert

Translation link: https://www.example.com

本文是作者 2019 年的一篇分享,里面的一些观点和使用的技术,对我们现在的开发依然有效,建议查看原文阅读,对本文翻译如有疑问,欢迎提 PR

First of all, the good news: When Google releases Chrome 80 in February 2020, it will include Google's implementation of "Increasingly better Cookies", which will make the web a safer place and help ensure users have better privacy (webmaster note: It's April 28, 2022, and Chrome has released multiple updates).

The bad news is that this new implementation is a major change in how browsers decide to send cookies to the server. First, if you use separate domains for your web application and authentication server, this change in Chrome will likely disrupt the session experience of some users. The second problem is that it may also prevent some of your users from logging out of your system correctly again.

1. First of all, what is this SameSite about?

Web 是一个非常开放的平台:Cookie 是在大约 20 年前设计的,以及 2011 年在 RFC 6265中重新审视该设计时,跨站请求伪造 (CSRF) 攻击和过度用户跟踪还不是什么大事。

In short, normal cookie specifications say that if a cookie is set for a specific domain, it will be sent to that domain with the cookie on every request made by the browser. Whether or not you navigate directly to the domain, if the browser just loads resources (i.e. images) from the domain, send a POST request to it or embed part of it in the iframe. But perhaps for the latter possibility, you don't want your browser to automatically send user session cookies to your server, because this would allow any website to execute JavaScript for requests from your server in the user's context without attracting their attention.

为了防止这种情况发生, SameSite cookie 规范 是在 2016 年起草的。它让您可以更好地控制何时应该或不应该发送 cookie:当您设置 cookie 时,您现在可以为每个 cookie 明确指定浏览器何时应将其添加到请求。为此,当浏览器位于您自己的域中时,它引入了同站点 cookie 的概念,而当浏览器在不同域中导航但向您的域发送请求时,它引入了跨站点 cookie 的概念。

为了向后兼容,相同站点 cookie 的默认设置并没有改变以前的行为。您必须选择加入该新功能并明确设置您的 cookie SameSite=LaxSameSite=Strict 使其更安全。这已在 .NET Framework(包括.NET CORE) 和所有常见浏览器中实现。 Lax 意味着,cookie 将在初始导航时发送到服务器, Strict 意味着 cookie 只会在您已经在该域上时发送(即初始导航后的第二个请求)。

遗憾的是,这项新功能的采用速度很慢(根据 2019 年 3 月 Chrome 的遥测数据 【来源 】,全球范围内 Chrome 上处理的所有 cookie 中只有 0.1% 使用 SameSite 标志)。

谷歌决定推动采用该功能。为了强制执行,他们决定更改世界上最常用的浏览器的默认设置:Chrome 80 将 必须 指定一个新的设置 SameSite=None 来保留处理 cookie 的旧方式,如果您像旧规范建议的那样省略 SameSite 字段,它将 cookie 视为使用 SameSite=Lax.

请注意: 该设置 SameSite=None 仅在 cookie 也被标记为 Secure 并需要 HTTPS 连接时才有效。

更新: 如果您想了解有关 SameSite cookie 的更多背景信息,有一篇包含 所有细节的新文章

2. Does this affect me? If so, how?

如果您有一个单页面 Web 应用程序 (SPA),它针对托管在不同域上的身份提供者(IdP,例如 IdentityServer 4)进行身份验证,并且该应用程序使用所谓的静默令牌刷新,您就会受到影响。

When you log in to IdP, it sets a session cookie for your users, which comes from the IdP domain. At the end of the authentication process, applications from different domains receive some kind of access token, which usually won't last long. When the token expires, the application will no longer be able to access the resource server (API), and it would be a very bad user experience if the user had to log in again every time this happened.

To prevent this, you can use silent token refresh. In this case, the application creates an iframe that is invisible to the user and starts the authentication process again in the iframe. IdP's website is loaded in iframe, and if the browser sends a session cookie along IdP, the user is recognized and a new token is issued.

现在 iframe 存在于托管在应用程序域中的 SPA 中,其内容来自 IdP 域。如果 cookie 明确指出 SameSite=None,Chrome 80 只会将该 cookie 从 iframe 发送到 IdP,这被认为是跨站点请求。 如果不是这种情况,您的静默令牌刷新将在 2 月 Chrome 80 发布时中断。

There are other situations that may cause problems for you: First, if you embed elements in a web application or website that originate from another domain, such as autoplay settings for videos, and these require cookies to function properly, these will also require setting SameSite policies. The same applies if your application requires a third-party API from a browser that relies on cookie authentication.

_Note: _Obviously, you can only change the cookie behavior of your own server with regard to cookie settings. If you happen to use elements in other domains that are not under your control, you need to contact a third party and ask them to change cookies when problems arise.

3. Okay, I will change my code and set SameSite to None. I can now, right?

不幸的是,Safari 有一个“错误”。此错误导致 Safari 无法将新引入的值 None 识别为 SameSite 设置的有效值。当 Safari 遇到无效值时,它会将 SameSite=Strict 当作已指定的设置,并且不会将会话 cookie 发送到 IdP。此错误已在 iOS 13 和 macOS 10.15 Catalina 上的 Safari 13 中修复,但不会向后移植到 macOS 10.14 Mojave 和 iOS 12,它们仍然拥有非常大的用户群。

所以,我们现在陷入了两难境地:要么我们忽略 SameSite 策略,我们的 Chrome 用户无法进行静默刷新,要么我们设置 SameSite=None 并锁定 iPhone、iPad 和 Mac 用户无法更新,或者旧设备无法更新到最新版本的 iOS 和 macOS。

4. Is there any way to be sure I'm affected?

幸运的是,是的。如果您已经设置 SameSite=None,您可能已经注意到您的应用程序或网站在 iOS 12 和 macOS 10.4 上的 Safari 中无法正常工作。如果没有,请确保在这些版本的 Safari 中测试您的应用程序或网站。

If you don't set SameSite values at all, you just need to open your application in Chrome and open developer tools. You will see the following warnings:

A cookie associated with a cross-site resource at {cookie domain} was set without the `SameSite` attribute.
A future release of Chrome will only deliver cookies with cross-site requests if they are set with `SameSite=None` and `Secure`.
You can review cookies in developer tools under Application>Storage>Cookies and see more details at
https://www.chromestatus.com/feature/5088147346030592 and
https://www.chromestatus.com/feature/5633521622188032.

如果您已经设置 SameSite=None 但忘了设置 Secure 标志,您将收到以下警告:

A cookie associated with a resource at {cookie domain} was set with `SameSite=None` but without `Secure`.
A future release of Chrome will only deliver cookies marked `SameSite=None` if they are also marked `Secure`.
You can review cookies in developer tools under Application>Storage>Cookies and
see more details at https://www.chromestatus.com/feature/5633521622188032.

5. So, how can I really solve this problem? I need Chrome and Safari to use normally.

我们,也就是我的同事 Boris Wilhelms 和我自己,对该主题进行了一些研究,并找到且验证了解决方案。微软的 Barry Dorrans 也有一篇 关于这个问题的好博文。该解决方案并不美观,遗憾的是需要在服务器端进行浏览器嗅探,但这是一个简单的解决方案,在过去的几周里,我们已经在我们的几个客户项目中成功实现了这一点。

要解决这个问题,我们首先需要确保需要通过跨站点请求传输的 cookie(例如我们的会话 cookie)设置为 SameSite=NoneSecure。我们需要在项目代码中找到该 cookie 的选项并进行相应调整。这解决了 Chrome 的问题并引入了 Safari 问题。

然后我们将以下类和代码片段添加到项目中。这会在 ASP.NET Core Web 应用程序中添加和配置 cookie 策略。此策略将检查是否设置了 cookie 为 SameSite=None 。如果是这种情况,它将检查浏览器的用户代理,并确定这是否是一个浏览器的设置有问题,比如我们受影响的 Safari 版本。如果也是这种情况,它会将 cookies SameSite 值设置为unspecified(未指定),这反过来将完全阻止设置 SameSite,从而为这些浏览器重新创建当前默认行为。

请注意: 此处提供的解决方案适用于 .NET Core。对于完整的基于 .NET Framework 的项目,您需要查看Barry Dorran 的帖子中指定的版本之一 。

5.1 Classes to add to your project

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

namespace Microsoft.Extensions.DependencyInjection
{
   public static class SameSiteCookiesServiceCollectionExtensions
   {
      /// <summary>
      /// -1 defines the unspecified value, which tells ASPNET Core to NOT
      /// send the SameSite attribute. With ASPNET Core 3.1 the
      /// <seealso cref="SameSiteMode" /> enum will have a definition for
      /// Unspecified.
      /// </summary>
      private const SameSiteMode Unspecified = (SameSiteMode) (-1);

      /// <summary>
      /// Configures a cookie policy to properly set the SameSite attribute
      /// for Browsers that handle unknown values as Strict. Ensure that you
      /// add the <seealso cref="Microsoft.AspNetCore.CookiePolicy.CookiePolicyMiddleware" />
      /// into the pipeline before sending any cookies!
      /// </summary>
      /// <remarks>
      /// Minimum ASPNET Core Version required for this code:
      ///   - 2.1.14
      ///   - 2.2.8
      ///   - 3.0.1
      ///   - 3.1.0-preview1
      /// Starting with version 80 of Chrome (to be released in February 2020)
      /// cookies with NO SameSite attribute are treated as SameSite=Lax.
      /// In order to always get the cookies send they need to be set to
      /// SameSite=None. But since the current standard only defines Lax and
      /// Strict as valid values there are some browsers that treat invalid
      /// values as SameSite=Strict. We therefore need to check the browser
      /// and either send SameSite=None or prevent the sending of SameSite=None.
      /// Relevant links:
      /// - https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1
      /// - https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
      /// - https://www.chromium.org/updates/same-site
      /// - https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
      /// - https://bugs.webkit.org/show_bug.cgi?id=198181
      /// </remarks>
      /// <param name="services">The service collection to register <see cref="CookiePolicyOptions" /> into.</param>
      /// <returns>The modified <see cref="IServiceCollection" />.</returns>
      public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
      {
         services.Configure<CookiePolicyOptions>(options =>
         {
            options.MinimumSameSitePolicy = Unspecified;
            options.OnAppendCookie = cookieContext =>
               CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
            options.OnDeleteCookie = cookieContext =>
               CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
         });

         return services;
      }

      private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
      {
         if (options.SameSite == SameSiteMode.None)
         {
            var userAgent = httpContext.Request.Headers["User-Agent"].ToString();

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

      /// <summary>
      /// Checks if the UserAgent is known to interpret an unknown value as Strict.
      /// For those the <see cref="CookieOptions.SameSite" /> property should be
      /// set to <see cref="Unspecified" />.
      /// </summary>
      /// <remarks>
      /// This code is taken from Microsoft:
      /// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
      /// </remarks>
      /// <param name="userAgent">The user agent string to check.</param>
      /// <returns>Whether the specified user agent (browser) accepts SameSite=None or not.</returns>
      private static bool DisallowsSameSiteNone(string userAgent)
      {
         // 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.
         // Notes from Thinktecture:
         // Regarding https://caniuse.com/#search=samesite iOS versions lower
         // than 12 are not supporting SameSite at all. Starting with version 13
         // unknown values are NOT treated as strict anymore. Therefore we only
         // need to check version 12.
         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.
         // Notes from Thinktecture:
         // Regarding https://caniuse.com/#search=samesite MacOS X versions lower
         // than 10.14 are not supporting SameSite at all. Starting with version
         // 10.15 unknown values are NOT treated as strict anymore. Therefore we
         // only need to check version 10.14.
         if (userAgent.Contains("Safari")
            && userAgent.Contains("Macintosh; Intel Mac OS X 10_14")
            && userAgent.Contains("Version/"))
         {
            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.
         // Notes from Thinktecture:
         // We can not validate this assumption, but we trust Microsofts
         // evaluation. And overall not sending a SameSite value equals to the same
         // behavior as SameSite=None for these old versions anyways.
         if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
         {
            return true;
         }

         return false;
      }
   }
}

To use this cookie policy, you need to add the following to your launch code:

public void ConfigureServices(IServiceCollection services)
{
   // Add this
   services.ConfigureNonBreakingSameSiteCookies();
}

public void Configure(IApplicationBuilder app)
{
   // Add this before any other middleware that might write cookies
   app.UseCookiePolicy();

   // This will write cookies, so make sure it's after the cookie policy
   app.UseAuthentication();
}

6. Okay. Am I finished now?

除了彻底的测试,特别是在 Chrome 79 中激活了“默认 cookie 的 SameSite”标志以及 macOS 和 iOS 上受影响的 Safari 版本,是的,你现在应该没事了。要在 Chrome 79 中进行测试,请导航到 chrome://flags、搜索 samesite 并启用该 SameSite by default cookies 标志。重新启动浏览器,您可以立即测试即将发生的更改。

Seriously: Make sure your silent refreshes-or usually cross-site requests that require cookies-can still run on these devices and browsers.

7. Can't I simply wait for my authentication server vendor to resolve this issue for me?

这是不太可能的。在我们这里的具体示例中,实际上管理 cookie 的不是 IdentityServer 本身。IdentityServer 依赖于 ASP.NET Core 框架的内置身份验证系统,这是管理会话 cookie 的地方。虽然 ASP.NET Core 框架已更新以支持新 SameSiteNone 和技术设置 Unspecified (不发送 SameSite ), 但微软表示 他们不能直接在 ASP.NET Core 中引入用户代理嗅探。所以这真的取决于你和你现有的项目。

8. summary

Chrome 将很快(2020 年 2 月)更改其处理 cookie 的默认行为。将来,它将默认 SameSite 被明确设置为None标志 和 Secure 标志设置,以允许将 cookie 添加到某些跨站点请求。如果你这样做,常见版本的 Safari 就会对此感到厌烦。

为确保所有浏览器都满意,您将所有受影响的 cookie 设置为 SecureSameSite=None,然后添加一个 cookie 策略(如上所示的代码),该策略可以覆盖这些设置并再次为无法对 None 正确解释该值的浏览器删除SameSite标志.

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读