SameSite是一种IETF草案,旨在针对跨站点请求伪造(CSRF)攻击提供某些防护。 SameSite 2019 草案:
SameSite=Lax
。SameSite=None
的 cookie 应标记为 Secure
。Lax
适用于大多数应用 cookie。 某些形式的身份验证,例如OpenID connect (OIDC)和ws-federation默认为基于 POST 的重定向。 基于后期的重定向会触发 SameSite 浏览器保护,因此,对这些组件禁用了 SameSite。 由于请求的流动方式不同,大多数OAuth登录名不受影响。
None
参数会导致实现之前2016草案标准(例如,iOS 12)的客户端的兼容性问题。 请参阅本文档中的支持旧版浏览器。
发出 cookie 的每个 ASP.NET Core 组件都需要确定 SameSite 是否合适。
Httpcontext.current默认值为 Unspecified
,这意味着,不会向 cookie 中添加 SameSite 属性,客户端将使用其默认行为(对于新浏览器而言,对于旧浏览器则为 "无")。 下面的代码演示如何将 cookie SameSite 值更改为 SameSiteMode.Lax
:
HttpContext.Response.Cookies.Append( "name", "value", new CookieOptions() { SameSite = SameSiteMode.Lax });
发出 cookie 的所有 ASP.NET Core 组件都用适用于其方案的设置替代前面的默认值。 先前重写的默认值尚未更改。
ASP.NET Core 3.1 和更高版本提供了以下 SameSite 支持:
SameSiteMode.None
的行为 SameSite=None
SameSiteMode.Unspecified
以省略 SameSite 属性。Unspecified
。 某些使用 cookie 的组件会将值设置得更加特定于其应用场景。 有关示例,请参阅上表。在 ASP.NET Core 3.0 及更高版本中,SameSite 默认值已更改,以避免与客户端默认值不一致发生冲突。 以下 Api 已将默认值从 SameSiteMode.Lax
更改为 -1
,以避免发出这些 cookie 的 SameSite 属性:
CookieOptions
的工厂SameSite 支持在2.0 中第一次 ASP.NET Core 实现,使用2016 草案标准。 2016标准已选择加入。 ASP.NET Core 选择在默认情况下 Lax
的几个 cookie。 在遇到身份验证的几个问题后,大多数 SameSite 使用已禁用。
2019年11月发布了修补程序,从2016标准版更新为2019标准。 SameSite 规范的2019草案:
SameSite=Lax
。SameSite=None
以便启用跨站点传递的 cookie 应标记为 Secure
。 None
是选择退出的新项。2016 SameSite 标准规定,未知值必须被视为 SameSite=Strict
值。 从支持 2016 SameSite 标准的旧版浏览器访问的应用可能会在收到值为 "None
" 的 SameSite 属性时中断。 如果 Web 应用要支持较旧的浏览器,则必须实现浏览器检测。 ASP.NET Core 不会实现浏览器检测,因为用户代理值非常稳定且频繁更改。 Microsoft.AspNetCore.CookiePolicy 中的扩展点允许插入特定于用户代理的逻辑。
在 Startup.Configure
中,添加调用 UseCookiePolicy 的代码,然后调用 UseAuthentication 或任何写入 cookie 的方法:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseCookiePolicy(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); }
在 Startup.ConfigureServices
中,添加类似于下面的代码:
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); }); services.AddRazorPages(); } private void CheckSameSite(HttpContext httpContext, CookieOptions options) { if (options.SameSite == SameSiteMode.None) { var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent)) { options.SameSite = SameSiteMode.Unspecified; } } }
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.MinimumSameSitePolicy = (SameSiteMode)(-1); options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); }); services.AddRazorPages(); } private void CheckSameSite(HttpContext httpContext, CookieOptions options) { if (options.SameSite == SameSiteMode.None) { var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent)) { options.SameSite = (SameSiteMode)(-1); } } }
在前面的示例中,MyUserAgentDetectionLib.DisallowsSameSiteNone
是一个用户提供的库,用于检测用户代理是否不支持 SameSite None
:
if (MyUserAgentDetectionLib.DisallowsSameSiteNone(userAgent)) { options.SameSite = SameSiteMode.Unspecified; }
下面的代码演示 DisallowsSameSiteNone
方法示例:
警告
以下代码仅用于演示:
public static bool DisallowsSameSiteNone(string userAgent) { // Check if a null or empty string has been passed in, since this // will cause further interrogation of the useragent to fail. if (String.IsNullOrWhiteSpace(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、ADAL 或所使用的任何库,测试 Safari 12、Safari 13 和基于 WebKit 的 OS 样式登录。 问题取决于基础 OS 版本。 已知 OSX Mojave (10.14)和 iOS 12 与新的 SameSite 行为存在兼容性问题。 将 OS 升级到 OSX Catalina (10.15)或 iOS 13 会解决此问题。 Safari 当前没有用于测试新规范行为的选择标记。
可以在版本 68 + 上测试对新标准的 Firefox 支持,方法是在 "about:config
" 页面上选择 "network.cookie.sameSite.laxByDefault
的功能标志。 以前版本的 Firefox 没有出现兼容性问题的报告。
Edge 支持旧的 SameSite 标准。 边缘版本44与新的标准没有任何已知的兼容性问题。
在 edge://flags/#same-site-by-default-cookies
页上设置 SameSite 标志。 未发现边缘 Chromium 的兼容性问题。
Electron 的版本包括较早版本的 Chromium。 例如,团队使用的 Electron 版本为 Chromium 66,该版本展示了较旧的行为。 你必须使用你的产品使用的 Electron 版本执行你自己的兼容性测试。 请参阅下一节中的支持旧版浏览器。