.NET Framework 4.7 具有对 SameSite 属性的内置支持,但它遵循原始标准。
修补后的行为将SameSite.None的含义更改为发出一个值为None的属性,而不是根本不发出该值。 如果不想发出值,可以将 Cookie 上的属性设置为 SameSite -1。
编写 SameSite 属性
下面是如何在 Cookie 上编写 SameSite 属性的示例;
// Create the cookie
HttpCookie sameSiteCookie = new HttpCookie("SameSiteSample");
// Set a value for the cookie
sameSiteCookie.Value = "sample";
// Set the secure flag, which Chrome's changes will require for SameSite none.
// Note this will also require you to be running on HTTPS
sameSiteCookie.Secure = true;
// Set the cookie to HTTP only which is good practice unless you really do need
// to access it client side in scripts.
sameSiteCookie.HttpOnly = true;
// Add the SameSite attribute, this will emit the attribute with a value of none.
// To not emit the attribute at all set the SameSite property to -1.
sameSiteCookie.SameSite = SameSiteMode.None;
// Add the cookie to the response cookie collection
Response.Cookies.Add(sameSiteCookie);
如果要以英语以外的语言阅读此信息,请在此 GitHub 讨论问题 中告知我们,如果你希望以本机语言查看代码注释。
表单身份验证 Cookie 的默认 sameSite 属性是在表单身份验证设置中的 cookieSameSite 参数里配置的 web.config
<system.web>
<authentication mode="Forms">
<forms name=".ASPXAUTH" loginUrl="~/" cookieSameSite="None" requireSSL="true">
</forms>
</authentication>
</system.web>
会话状态的默认 sameSite 属性也在会话设置的“cookieSameSite”参数中设置 web.config
<system.web>
<sessionState cookieSameSite="None">
</sessionState>
</system.web>
2019 年 11 月对 .NET 的更新将窗体身份验证和会话的默认设置更改为 lax 最兼容的设置,但是如果将页面嵌入 iframe,则可能需要将此设置还原为“无”,然后添加下面所示的 拦截 代码来根据浏览器功能调整 none 行为。
运行示例
如果运行示例项目,请在初始页面上加载浏览器调试器,并使用它查看网站的 Cookie 集合。
若要在 Edge 和 Chrome 中执行此操作,请按 F12,然后选择 Application 选项卡并单击 Cookies 部分中 Storage 选项下的站点 URL。
从上图中可以看到,单击“创建 Cookie”按钮时示例创建的 Cookie 具有 SameSite 属性值 Lax,与 示例代码中设置的值匹配。
截获你不控制的 Cookie
.NET 4.5.2 引入了一个新事件,用于截获标头的写入。 Response.AddOnSendingHeaders 这可用于在 Cookie 返回到客户端计算机之前截获 Cookie。 在示例中,我们将事件连接到静态方法,该方法检查浏览器是否支持新的 SameSite 更改,如果不是,则更改 Cookie,以在设置新 None 值时不发出属性。
请参阅global.asax以了解连接事件的示例,SameSiteCookieRewriter.cs以查看处理事件和调整 Cookie sameSite 属性的示例。
public static void FilterSameSiteNoneForIncompatibleUserAgents(object sender)
{
HttpApplication application = sender as HttpApplication;
if (application != null)
{
var userAgent = application.Context.Request.UserAgent;
if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
{
HttpContext.Current.Response.AddOnSendingHeaders(context =>
{
var cookies = context.Response.Cookies;
for (var i = 0; i < cookies.Count; i++)
{
var cookie = cookies[i];
if (cookie.SameSite == SameSiteMode.None)
{
cookie.SameSite = (SameSiteMode)(-1); // Unspecified
}
}
});
}
}
}
你可以用差不多的方式更改特定命名的 Cookie 行为;在支持None值的浏览器中,下面的示例将默认身份验证 Cookie 从Lax调整为None,而在不支持None的浏览器中,则删除 sameSite 属性。
public static void AdjustSpecificCookieSettings()
{
HttpContext.Current.Response.AddOnSendingHeaders(context =>
{
var cookies = context.Response.Cookies;
for (var i = 0; i < cookies.Count; i++)
{
var cookie = cookies[i];
// Forms auth: ".ASPXAUTH"
// Session: "ASP.NET_SessionId"
if (string.Equals(".ASPXAUTH", cookie.Name, StringComparison.Ordinal))
{
if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
{
cookie.SameSite = -1;
}
else
{
cookie.SameSite = SameSiteMode.None;
}
cookie.Secure = true;
}
}
});
}