- 在 ASP.NET Core 中使用 SameSite cookieWork with SameSite cookies in ASP.NET Core
- SameSite 测试示例代码SameSite test sample code
- .NET Core 对 sameSite 属性的支持.NET Core support for the sameSite attribute
- 12月修补程序行为更改December patch behavior changes
- 使用 SameSite 的 API 用法API usage with SameSite
- 历史记录和更改History and changes
- 受从 2016 SameSite 草案标准到2019草案标准的更改影响的 ApiAPIs impacted by the change from the 2016 SameSite draft standard to the 2019 draft standard
- 支持旧版浏览器Supporting older browsers
- 测试应用的 SameSite 问题Test apps for SameSite problems
- 其他资源Additional resources
在 ASP.NET Core 中使用 SameSite cookieWork with SameSite cookies in ASP.NET Core
本文内容
SameSite 是一种IETF草案标准,旨在提供一些针对跨站点请求伪造(CSRF)攻击的防护。最初在2016中起草草案标准版已在2019中更新。更新的标准与以前的标准不是向后兼容,以下是最明显的区别:
- 默认情况下,不带 SameSite 标头的 cookie 被视为
SameSite=Lax
。 SameSite=None
必须用于允许跨站点 cookie。- 断言
SameSite=None
的 cookie 也必须标记为Secure
。 - 使用
<iframe>
的应用程序可能会遇到sameSite=Lax
或sameSite=Strict
cookie 的问题,因为<iframe>
被视为跨站点方案。 - 2016 标准不允许使用值
SameSite=None
,并导致某些实现将此类 cookie 视为SameSite=Strict
。请参阅本文档中的支持旧版浏览器。
SameSite=Lax
设置适用于大多数应用程序 cookie。某些形式的身份验证,例如OpenID connect (OIDC)和ws-federation默认为基于 POST 的重定向。基于后期的重定向会触发 SameSite 浏览器保护,因此,对这些组件禁用了 SameSite。由于请求的流动方式不同,大多数OAuth登录名不受影响。
发出 cookie 的每个 ASP.NET Core 组件都需要确定 SameSite 是否合适。
SameSite 测试示例代码SameSite test sample code
可下载和测试以下示例:
示例 | Document |
---|---|
.NET Core MVC | ASP.NET Core 2.1 MVC SameSite cookie 示例 |
.NET Core Razor Pages | ASP.NET Core 2.1 Razor Pages SameSite cookie 示例 |
可下载并测试以下示例:
示例 | Document |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages SameSite cookie 示例 |
.NET Core 对 sameSite 属性的支持.NET Core support for the sameSite attribute
由于2.2 年12月2019更新发布,.NET Core 支持 SameSite 的2019草案标准。开发人员能够使用 HttpCookie.SameSite
属性以编程方式控制 sameSite 属性的值。如果将 SameSite
属性设置为 Strict、宽松或 None,则会在网络上用 cookie 写入这些值。如果将其设置为(SameSiteMode)(-1),则表示网络上不应包含 cookie 为的 sameSite 属性
var cookieOptions = new CookieOptions
{
// Set the secure flag, which Chrome's changes will require for SameSite none.
// Note this will also require you to be running on HTTPS.
Secure = true,
// Set the cookie to HTTP only which is good practice unless you really do need
// to access it client side in scripts.
HttpOnly = true,
// Add the SameSite attribute, this will emit the attribute with a value of none.
// To not emit the attribute at all set
// SameSite = (SameSiteMode)(-1)
SameSite = SameSiteMode.None
};
// Add the cookie to the response cookie collection
Response.Cookies.Append("MyCookie", "cookieValue", cookieOptions);
.NET Core 3.0 支持更新后的 SameSite 值,并将额外的枚举值 SameSiteMode.Unspecified
添加到 SameSiteMode
枚举。此新值指示不应向 cookie 发送任何 sameSite。
12月修补程序行为更改December patch behavior changes
.NET Framework 和 .NET Core 2.1 的特定行为更改是 SameSite
属性解释 None
值的方式。在修补程序的值 None
表示 "根本不发出属性" 之后,修补程序表示 "发出值为 None
的属性"。修补后 SameSite
值为 (SameSiteMode)(-1)
会导致不发出属性。
Forms 身份验证和会话状态 cookie 的默认 SameSite 值已从 None
更改为 Lax
。
使用 SameSite 的 API 用法API usage with 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 属性。 - 所有 cookie Api 默认为
Unspecified
。某些使用 cookie 的组件会将值设置得更加特定于其应用场景。有关示例,请参阅上表。
在 ASP.NET Core 3.0 及更高版本中,SameSite 默认值已更改,以避免与客户端默认值不一致发生冲突。以下 Api 已将默认值从 SameSiteMode.Lax
更改为 -1
,以避免发出这些 cookie 的 SameSite 属性:
- 与HttpContext一起使用的 CookieOptions
- CookieBuilder 用作
CookieOptions
的工厂 - CookiePolicyOptions.MinimumSameSitePolicy
历史记录和更改History and changes
SameSite 支持在2.0 中第一次 ASP.NET Core 实现,使用2016 草案标准。2016标准已选择加入。ASP.NET Core 选择在默认情况下 Lax
的几个 cookie。在遇到身份验证的几个问题后,大多数 SameSite 使用已禁用。
2019年11月发布了修补程序,从2016标准版更新为2019标准。SameSite 规范的2019草案:
- 不向后兼容2016草案。有关详细信息,请参阅本文档中的支持旧版浏览器。
- 指定默认情况下将 cookie 视为
SameSite=Lax
。 - 指定显式断言
SameSite=None
以便启用跨站点传递的 cookie 应标记为Secure
。None
是选择退出的新项。 - 为 ASP.NET Core 2.1、2.2 和3.0 颁发的修补程序支持。ASP.NET Core 3.1 具有附加的 SameSite 支持。
- 默认情况下,计划在2020 年2月启用。浏览器已开始在2019中移动到此标准。
受从 2016 SameSite 草案标准到2019草案标准的更改影响的 ApiAPIs impacted by the change from the 2016 SameSite draft standard to the 2019 draft standard
- SameSiteMode
- CookieOptions. SameSite
- CookieBuilder. SameSite
- CookiePolicyOptions.MinimumSameSitePolicy
- Microsoft.Net.Http.Headers.SameSiteMode
- Microsoft.Net.Http.Headers.SetCookieHeaderValue.SameSite
支持旧版浏览器Supporting older browsers
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 问题Test apps for SameSite problems
与远程站点(如通过第三方登录)交互的应用需要:
- 测试多个浏览器上的交互。
- 应用本文档中讨论的CookiePolicy 浏览器检测和缓解措施。
使用可选择新的 SameSite 行为的客户端版本测试 web 应用。Chrome、Firefox 和 Chromium Edge 都具有可用于测试的新的可选功能标志。应用应用 SameSite 修补程序后,请对其进行测试,使其与早期版本的客户端版本(尤其是 Safari)有关详细信息,请参阅本文档中的支持旧版浏览器。
用 Chrome 测试Test with 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 。
从未加 80.0.3975.0
的抑制版本开始,可以使用新的标志 —enable-features=SameSiteDefaultChecksMethodRigorously
禁用宽松的 + 后续暂时缓解功能,以允许在删除缓解功能的最终状态下测试站点和服务。有关详细信息,请参阅 Chromium 项目SameSite Updates
用 Safari 测试Test with Safari
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 当前没有用于测试新规范行为的选择标记。
用 Firefox 测试Test with Firefox
可以在版本 68 + 上测试对新标准的 Firefox 支持,方法是在 "about:config
" 页面上选择 "network.cookie.sameSite.laxByDefault
的功能标志。以前版本的 Firefox 没有出现兼容性问题的报告。
通过 Edge 浏览器进行测试Test with Edge browser
Edge 支持旧的 SameSite 标准。边缘版本44与新的标准没有任何已知的兼容性问题。
带边缘测试(Chromium)Test with Edge (Chromium)
在 edge://flags/#same-site-by-default-cookies
页上设置 SameSite 标志。未发现边缘 Chromium 的兼容性问题。
用 Electron 进行测试Test with Electron
Electron 的版本包括较早版本的 Chromium。例如,团队使用的 Electron 版本为 Chromium 66,该版本展示了较旧的行为。你必须使用你的产品使用的 Electron 版本执行你自己的兼容性测试。请参阅下一节中的支持旧版浏览器。
其他资源Additional resources
示例 | Document |
---|---|
.NET Core MVC | ASP.NET Core 2.1 MVC SameSite cookie 示例 |
.NET Core Razor Pages | ASP.NET Core 2.1 Razor Pages SameSite cookie 示例 |
示例 | Document |
---|---|
.NET Core Razor Pages | ASP.NET Core 3.1 Razor Pages SameSite cookie 示例 |