使用英语阅读

通过


SameSite Cookie 和用于 .NET 的开放 Web 界面(OWIN)

作者:Rick Anderson

SameSite是 IETF 草案,旨在提供一些保护,防止跨站点请求伪造(CSRF)攻击。 SameSite 2019 草稿

  • 默认情况下,将 Cookie 视为 SameSite=Lax
  • 声明显式断言 SameSite=None 以启用跨站点传递的 Cookie 应标记为 Secure

Lax 适用于大多数应用 Cookie。 某些形式的身份验证(如 OpenID Connect (OIDC) 和 WS-Federation)默认为基于 POST 的重定向。 基于 POST 的重定向会触发 SameSite 浏览器保护,因此 SameSite 对这些组件禁用。 由于请求流的方式差异,大多数 OAuth 登录不会受到影响。 所有其他组件默认未设置SameSite并使用客户端默认行为(旧或新)。

None 参数会导致实现以前的 2016 草稿标准的 客户端(例如 iOS 12)的兼容性问题。 请参阅本文档中的支持较旧浏览器

发出 Cookie 的每个 OWIN 组件都需要确定是否 SameSite 合适。

有关本文的 ASP.NET 4.x 版本,请参阅 ASP.NET 中的 SameSite cookie。

使用 SameSite 的 API 用法

Microsoft.OwinSameSite有自己的实现:

  • 这并不直接依赖于其中的 System.Web一个。
  • SameSite 适用于包、.NET 4.5 及更高版本可 Microsoft.Owin 面向的所有版本。
  • 仅 SystemWebCookieManager 组件直接与类System.WebHttpCookie交互。

SystemWebCookieManager取决于用于启用SameSite支持的 .NET 4.7.2 System.Web API,以及用于更改行为的修补程序。

OWIN 和 System.Web 响应 Cookie 集成问题概述了使用SystemWebCookieManager原因。 SystemWebCookieManager 建议在 System.Web运行时使用 。

以下代码设置为SameSiteLax

owinContext.Response.Cookies.Append("My Key", "My Value", new CookieOptions()
{
    SameSite = SameSiteMode.Lax
});

以下 API 使用 SameSite

历史记录和更改

Microsoft.Owin 从未支持 SameSite 2016 年草案标准

对 SameSite 2019 草稿的支持仅在 4.1.0 及更高版本中可用Microsoft.Owin。 以前版本没有修补程序。

2019 年 SameSite 规范草案:

  • 不与 2016 草案向后兼容。 有关详细信息,请参阅本文档中的支持较旧浏览器
  • 默认情况下,指定将 Cookie 视为 SameSite=Lax
  • 指定显式断言 SameSite=None 以便启用跨站点交付的 Cookie 应标记为 SecureNone 是要选择退出的新项。
  • 计划在 2020 年 2 月Chrome 默认启用。 浏览器已开始在 2019 年迁移到此标准。
  • 根据知识库文章中所述发布的修补程序支持。 有关详细信息,请参阅 支持 .NET Framework 中的 SameSite 的知识库文章。

支持较旧浏览器

2016 SameSite 年标准要求将未知值视为 SameSite=Strict 值。 从支持 2016 SameSite 标准的较旧浏览器访问的应用在获取值为 <a0SameSite/> 的属性时可能会中断。 如果 Web 应用打算支持较旧浏览器,则必须实现浏览器检测。 ASP.NET 不实现浏览器检测,因为用户代理值高度易失,并且经常更改。 ICookieManager 中的扩展点允许插入特定于用户代理的逻辑。

Startup.Configuration 中,添加类似于以下内容的代码:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseOpenIdConnectAuthentication(
             new OpenIdConnectAuthenticationOptions
             {
                 // … Your preexisting options … 
                 CookieManager = new SameSiteCookieManager(
                                     new SystemWebCookieManager())
             });

        // Remaining code removed for brevity.

上述代码需要 .NET 4.7.2 或更高版本 SameSite 的修补程序。

以下代码演示了 SameSiteCookieManager以下代码的示例实现:

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 (options.SameSite == Microsoft.Owin.SameSiteMode.None 
                             && DisallowsSameSiteNone(context))
        {
            options.SameSite = null;
        }
    }

在前面的示例中, DisallowsSameSiteNone 在方法中 CheckSameSite 调用。 DisallowsSameSiteNone是一种用户方法,用于检测用户代理是否不支持SameSiteNone

private void CheckSameSite(IOwinContext context, CookieOptions options)
{
    if (options.SameSite == Microsoft.Owin.SameSiteMode.None 
                         && DisallowsSameSiteNone(context))
    {
        options.SameSite = null;
    }
}

下面的代码演示示例 DisallowsSameSiteNone 方法:

警告

下面的代码仅用于演示:

  • 不应将其视为完整代码。
  • 它不进行维护或受支持。
public static bool DisallowsSameSiteNone(IOwinContext context)
{
    var userAgent = context.Request.Headers["User-Agent"];
    
    if (string.IsNullOrEmpty(userAgent))
    {
        return false;
    }
    
    // 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.
    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.
    if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
        userAgent.Contains("Version/") && userAgent.Contains("Safari"))
    {
        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.
    if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
    {
        return true;
    }

    return false;
}

针对 SameSite 问题测试应用

与远程站点交互(例如通过第三方登录)的应用需要:

使用可以选择加入新 SameSite 行为的客户端版本测试 Web 应用。 Chrome、Firefox 和 Chromium Edge 都具有可用于测试的新的“选择加入”功能标志。 应用应用 SameSite 修补程序后,使用较旧的客户端版本(尤其是 Safari)对其进行测试。 有关详细信息,请参阅本文档中的支持较旧浏览器

使用 Chrome 测试

Chrome 78+ 会提供误导性的结果,因为它实施了临时缓解。 Chrome 78+ 临时缓解措施允许使用两分钟内产生的 Cookie。 启用合适的测试标志后,Chrome 76 或 77 会提供更准确的结果。 测试新SameSite行为切换chrome://flags/#same-site-by-default-cookies“已启用”。 据报告,较旧版本的 Chrome(75 及更早版本)会在使用新的 None 设置时失败。 请参阅本文档中的支持较旧浏览器

Google 不提供较旧的 chrome 版本。 按照下载 Chromium 的说明测试较旧版本的 Chrome。 请勿从通过搜索较旧版本 chrome 而提供的链接下载 Chrome。

使用 Safari 测试

Safari 12 严格执行以前的草稿,当新 None 值位于 Cookie 中时失败。 可通过本文档中浏览器检测代码支持较旧浏览器避免 None。 使用 MSAL 或正在使用的任何库测试 Safari 12、Safari 13 和基于 WebKit 的 OS 样式登录。 问题取决于基础 OS 版本。 已知 OSX Mojave (10.14) 和 iOS 12 与新 SameSite 行为存在兼容性问题。 将操作系统升级到 OSX Catalina (10.15) 或 iOS 13 会解决此问题。 Safari 当前没有用于测试新规范行为的选择加入标志。

使用 Firefox 测试

通过在具有功能标志 network.cookie.sameSite.laxByDefaultabout:config 页面上选择加入,可在版本 68+ 上测试 Firefox 对新标准的支持。 较旧版本的 Firefox 未报告兼容性问题。

使用 Edge 浏览器测试

Edge 支持旧 SameSite 标准。 Edge 版本 44 与新标准不存在任何已知的兼容性问题。

使用 Edge (Chromium) 测试

SameSite 标志在页面上设置 edge://flags/#same-site-by-default-cookies 。 未发现与 Edge Chromium 的兼容性问题。

使用 Electron 进行测试

Electron 的版本包括较早版本的 Chromium。 例如,Teams 使用的 Electron 版本为 Chromium 66,它显示了较旧的行为。 必须与产品使用的 Electron 版本执行自己的兼容性测试。 请参阅以下部分中的支持较旧浏览器

其他资源