SameSite是
HTTP cookie的2016年
扩展,旨在缓解跨站点请求伪造(CSRF)。 原始设计是一种选择加入功能,可以通过向cookie添加新的SameSite属性来使用。 它有两个值,即Lax和Strict。
将值设置为Lax表示Cookie应该在同一站点内的导航上发送,或通过GET导航从其他站点发送到您的站点。 严格值将cookie限制为仅来自同一站点的请求。 完全不设置该属性对cookie在请求中的流动方式没有任何限制。 OpenIdConnect身份验证操作(例如登录,注销)以及其他将POST请求从外部站点发送到请求该操作的站点的其他功能,可以使用cookie进行关联和/或CSRF保护。 这些操作将需要通过完全不设置属性来选择退出SameSite,以确保这些cookie将在其特殊请求流期间发送。
Google现在正在
更新标准,并在即将推出的Chrome版本中实施其建议的更改。 所做的更改将添加一个新的SameSite值“ None”,并将默认行为更改为“ Lax”。 这会中断OpenIdConnect登录,并可能破坏您的网站可能依赖的其他功能,这些功能将不得不使用其SameSite属性设置为“ None”值的cookie。
但是,遵循原始标准并且不知道新值的浏览器与使用新标准的浏览器具有不同的行为,因为SameSite标准指出,如果浏览器看到SameSite的值,则无法理解,因此应将该值视为“严格。” 这意味着您的.NET网站现在必须添加用户代理嗅探功能,以决定是否发送新的None值,或者根本不发送属性。

.NET将发布更新以更改.NET 4.7.2和.NET Core 2.1及更高版本中SameSite属性的行为,以反映Google对新值的引入。 如果您使用“检查更新”功能,.NET Framework的更新将于11月19日作为可选更新通过Microsoft Update和WSUS提供。 在12月10日,它将变得广泛可用并显示在Microsoft Update中,而您无需专门检查更新。 .NET Core 3.1将从11月的预览版1开始提供.NET Core更新。
.NET Core 3.1将包含一个
更新的枚举定义 SameSite.Unspecified,它将不设置SameSite属性。
Microsoft.Owin v4.1和.NET Core的OpenIdConnect中间件将在其.NET Framework和.NET更新的同时进行更新,但是我们无法将用户代理嗅探代码引入该框架中,必须在您的产品中实现网站代码。 代理嗅探的实现将根据您使用的ASP.NET或ASP.NET Core版本以及您希望支持的浏览器而有所不同。
对于带有Microsoft.Owin 4.1.0的ASP.NET 4.7.2,可以使用
ICookieManager来实现代理嗅探。
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 (DisallowsSameSiteNone(context) && options.SameSite == SameSiteMode.None) { options.SameSite = null; } } public static bool DisallowsSameSiteNone(IOwinContext context) { // TODO: Use your User Agent library of choice here. var userAgent = context.Request.Headers["User-Agent"]; return userAgent.Contains("BrokenUserAgent") || userAgent.Contains("BrokenUserAgent2") } }
然后配置OpenIdConnect设置以使用新的CookieManager;
app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { // … Your preexisting options … CookieManager = new SameSiteCookieManager(new SystemWebCookieManager()) });
SystemWebCookieManager将需要安装.NET 4.7.2或更高版本的SameSite修补程序才能正常工作。
对于ASP.NET Core,您应该安装补丁,然后在
cookie策略中实施代理嗅探代码。 对于3.1之前的版本,将SameSiteMode.Unspecified替换为(SameSiteMode)(-1)。
private void CheckSameSite(HttpContext httpContext, CookieOptions options) { if (options.SameSite > SameSiteMode.Unspecified) { var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); // TODO: Use your User Agent library of choice here. if (/* UserAgent doesn't support new behavior */) { // For .NET Core < 3.1 set SameSite = -1 options.SameSite = SameSiteMode.Unspecified; } } } 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); }); } public void Configure(IApplicationBuilder app) { app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies. app.UseAuthentication(); // … }
通过与Azure Active Directory团队进行的测试,我们发现以下检查适用于Azure Active Directory看到的所有不了解新值的普通用户代理。
public 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 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; }
此浏览器列表绝不规范,一旦更新到位,您应该验证系统支持的常见浏览器和其他用户代理的行为是否符合预期。
Chrome 80计划在2020年2月或2020年3月
启用新功能 ,包括在Chrome 79 Beta中添加的临时缓解措施。 如果要在没有缓解措施的情况下测试新行为,请使用Chromium76。
可下载旧版本的Chromium。
如果您无法在Chrome于2020年初转变为新行为时更新框架版本,则可以将OpenIdConnect流更改为Code流,而不是ASP.NET和ASP.NET Core使用的默认隐式流,但是这应被视为临时措施。
强烈建议您在11月发布更新的.NET Framework和.NET Core版本,并在Chrome所做的更改推出之前开始计划更新。