ASP.NET Core 3.1 Razor Pages SameSite cookie 示例

ASP.NET Core 3.0 对 SameSite 属性提供内置支持,包括用于禁止写入该属性的 SameSiteMode 属性值 Unspecified

IFramesOpenIdConnect 集成等高级方案以外,ASP.NET Core Identity 在很大程度上不受 SameSite cookie 的影响。

使用 Identity 时,不要添加任何 cookie 提供程序或调用 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)Identity 会执行这些操作。

写入 SameSite 属性

以下示例介绍如何在 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 the SameSite property to SameSiteMode.Unspecified.
    SameSite = SameSiteMode.None
};

// Add the cookie to the response cookie collection
Response.Cookies.Append(CookieName, "cookieValue", cookieOptions);

Cookie 身份验证、会话状态和各种其他组件通过 Cookie 选项设置其 sameSite 选项,例如

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.Cookie.SameSite = SameSiteMode.None;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.IsEssential = true;
    });

services.AddSession(options =>
{
    options.Cookie.SameSite = SameSiteMode.None;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.IsEssential = true;
});

在上面显示的代码中,cookie 身份验证和会话状态都将其 sameSite 属性设置为 None,发出值为 None 的属性,并将 Secure 属性设置为 true。

运行示例

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

Browser Debugger Cookie List

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

截获 cookie

若要截获 cookie,以便根据用户浏览器代理的支持来调整 none 值,你必须使用 CookiePolicy 中间件。 它必须放在 http 请求管道中任何写入 cookie 的组件之前,并在 ConfigureServices() 中进行配置。

若要将其插入管道,请在 Startup.csConfigure(IApplicationBuilder, IHostingEnvironment) 方法中使用 app.UseCookiePolicy()。 例如:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
       app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseSession();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

然后在 ConfigureServices(IServiceCollection services) 中配置 cookie 策略,以便在追加或删除 cookie 时调用帮助程序类,如下所示:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
        options.OnAppendCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
        options.OnDeleteCookie = cookieContext =>
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    });
}

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (SameSite.BrowserDetection.DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = SameSiteMode.Unspecified;
        }
    }
}

帮助程序函数 CheckSameSite(HttpContext, CookieOptions)

  • 在将 cookie 追加到请求或从请求中删除时调用。
  • 检查 SameSite 属性是否设置为 None
  • 如果 SameSite 设置为 None 并且已知当前用户代理不支持 none 属性值。 使用 SameSiteSupport 类完成检查:
    • SameSite 设置为不发出值,方法是将该属性设置为 (SameSiteMode)(-1)

更多信息

Chrome 更新ASP.NET Core SameSite 文档