SameSite Cookie 和用于 .NET 的开放 Web 界面(OWIN)
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。
Microsoft.Owin
SameSite
有自己的实现:
- 这并不直接依赖于其中的
System.Web
一个。 SameSite
适用于包、.NET 4.5 及更高版本可Microsoft.Owin
面向的所有版本。- 仅 SystemWebCookieManager 组件直接与类
System.Web
HttpCookie
交互。
SystemWebCookieManager
取决于用于启用SameSite
支持的 .NET 4.7.2 System.Web
API,以及用于更改行为的修补程序。
OWIN 和 System.Web 响应 Cookie 集成问题概述了使用SystemWebCookieManager
原因。 SystemWebCookieManager
建议在 System.Web
运行时使用 。
以下代码设置为SameSite
Lax
:
owinContext.Response.Cookies.Append("My Key", "My Value", new CookieOptions()
{
SameSite = SameSiteMode.Lax
});
以下 API 使用 SameSite
:
- Microsoft.Owin.SameSiteMode
- CookieOptions.SameSite
- CookieAuthenticationOptions 类
- CookieAuthenticationOptions.CookieSameSite
- ICookieManager
- SystemWebCookieManager
- SystemWebChunkingCookieManager
- CookieAuthenticationOptions.CookieManager
- OpenIdConnectAuthenticationOptions.CookieManager
Microsoft.Owin 从未支持 SameSite
2016 年草案标准。
对 SameSite 2019 草稿的支持仅在 4.1.0 及更高版本中可用Microsoft.Owin
。 以前版本没有修补程序。
2019 年 SameSite
规范草案:
- 不与 2016 草案向后兼容。 有关详细信息,请参阅本文档中的支持较旧浏览器。
- 默认情况下,指定将 Cookie 视为
SameSite=Lax
。 - 指定显式断言
SameSite=None
以便启用跨站点交付的 Cookie 应标记为Secure
。None
是要选择退出的新项。 - 计划在 2020 年 2 月由 Chrome 默认启用。 浏览器已开始在 2019 年迁移到此标准。
- 根据知识库文章中所述发布的修补程序支持。 有关详细信息,请参阅 支持 .NET Framework 中的 SameSite 的知识库文章。
2016 SameSite
年标准要求将未知值视为 SameSite=Strict
值。 从支持 2016 SameSite
标准的较旧浏览器访问的应用在获取值为 <SameSite
/> 的属性时可能会中断。 如果 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
是一种用户方法,用于检测用户代理是否不支持SameSite
None
:
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
行为的客户端版本测试 Web 应用。 Chrome、Firefox 和 Chromium Edge 都具有可用于测试的新的“选择加入”功能标志。 应用应用 SameSite
修补程序后,使用较旧的客户端版本(尤其是 Safari)对其进行测试。 有关详细信息,请参阅本文档中的支持较旧浏览器。
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 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 当前没有用于测试新规范行为的选择加入标志。
通过在具有功能标志 network.cookie.sameSite.laxByDefault
的 about:config
页面上选择加入,可在版本 68+ 上测试 Firefox 对新标准的支持。 较旧版本的 Firefox 未报告兼容性问题。
Edge 支持旧 SameSite
标准。 Edge 版本 44 与新标准不存在任何已知的兼容性问题。
SameSite
标志在页面上设置 edge://flags/#same-site-by-default-cookies
。 未发现与 Edge Chromium 的兼容性问题。
Electron 的版本包括较早版本的 Chromium。 例如,Teams 使用的 Electron 版本为 Chromium 66,它显示了较旧的行为。 必须与产品使用的 Electron 版本执行自己的兼容性测试。 请参阅以下部分中的支持较旧浏览器。