适用于 ASP.NET 4.7.2 C# WebForms 的 SameSite Cookie 示例

.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>

.NET 的 2019 年 11 月更新将表单身份验证和会话的默认设置更改为lax最兼容的设置,但如果将页面嵌入 iframe,则可能需要将此设置还原为“无”,然后添加下面显示的拦截代码,以便根据浏览器功能调整none行为。

运行示例

如果运行示例项目,请在初始页面上加载浏览器调试器,并使用它来查看站点的 Cookie 集合。 若要在 Edge 和 Chrome 中执行此操作,请按 F12,然后选择 Application 选项卡并单击 Storage 部分中 Cookies 选项下的站点 URL。

浏览器调试器 Cookie 列表

从上图中可以看到,单击“创建 Cookie”按钮时示例创建的 Cookie 的 SameSite 属性值 Lax示例代码中设置的值相匹配。

截获你无法控制的 Cookie

.NET 4.5.2 引入了一个新事件来截获标头的写入。 Response.AddOnSendingHeaders 这可用于在 Cookie 返回到客户端计算机之前截获 Cookie。 在示例中,我们将 事件连接到静态方法,该方法检查浏览器是否支持新的 sameSite 更改,如果不支持,则更改 Cookie 以在设置了新 None 值时不发出 属性。

有关挂接事件的示例,请参阅 global.asax;有关处理事件和调整 Cookie sameSite 属性的示例,请参阅 SameSiteCookieRewriter.cs

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;
            }
        }
    });
}

更多信息

Chrome 汇报

ASP.NET 文档

.NET SameSite 修补程序