ASP.NET Core 第三方验证时 Cookies 无法跨域问题

首次发布于2021-03-19 19:52

在开发ASP.NET Core Web程序,使用第三方登录验证服务的时候,如果程序配置为http协议并且使用Chromium内核的浏览器(Chrome、Edge等)进行调试时会发生如下错误
System.Exception: An error was encountered while handling the remote login.
System.Exception: Correlation failed.
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

如果查看页面的Cookies信息可以发现发生错误的原因是本地页面在发起第三方登录请求的跳转时,没有将Cookies中的Identity.External传递过去,原因是Chrome出于安全考虑进行了拦截。下面简单介绍原因,详情可以跳转到引用链接了解。

Cookie 的 SameSite 属性

Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪1

根据限制的严格程度可以将 SameSite 可以设置为三个值:

  • Strict - 最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。
  • Lax - 规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外(链接,预加载请求,GET 表单)。
  • None - 这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效2

Chrome 85 开始将Lax变为默认设置3

所以,如果使用较新版本的Chrome,即使将SameSite属性设为None4也无法跨域传递Cookies。

解决的办法

1、临时的办法:在浏览器输入chrome://flags/ 回车,找到 Cookies without SameSite must be secure,设为 Disable,重启浏览器即可。这个办法只是改变特定浏览器的行为,并不推荐。

2、使用 https:

IIS Express:修改项目的 launchSettings.json 的 iisExpress 的 sslPort,如改为44338,即可开启SSL(或右键项目属性,在Debug选项卡中开启SSL),首次运行时 Visual Studio 会提示导入自签证书,点击“是”就可以。这个方法可以解决开发阶段的第三方验证问题。

如果丢失 localhost 证书,通过 VS 启用 IIS Express 调试可重新安装(有时需重启VS),若浏览器仍提示不安全,重启浏览器即可。

Kestrel:方法一,直接参考 Configuring HTTPS in ASP.NET Core across different platforms

方法二(.Net 5以上版本可用,Core 3.1未测试过),使用 mkcert 工具,安装后,通过一条命令即可生成自签证书(包含两个文件example.pem、example-key.pem)。

将两个 pem 文件放在项目根目录,然后在 appsetting.json 加入如下配置节点,无需额外代码即可使用。6


  "Kestrel": {
    "Endpoints": {
      "HttpsFromPem": {
        "Url": "https://localhost:5001",
        "Certificate": {
          "Path": "./localhost.pem",
          "KeyPath": "./localhost-key.pem"
        }
      }
    }
  }

友情提示:如果需要在 Windows 下生成 pfx 证书,可使用 openssl,通过命令openssl pkcs12 -inkey example-key.pem -in example.pem/example.cert -export -out example.pfx即可生成。

注意:如下代码在 Windows 下(.Net 5)无法奏效。原因是通过这种方式只能将 private key 导入内存,而 Windows 的 Kestrel 需要 private key 加载到系统密钥集才能工作。

webBuilder.UseKestrel(opt =>
{
    var cerPemPath = Path.Combine(AppContext.BaseDirectory, "localhost.pem");
    var cerKeyPemPath = Path.Combine(AppContext.BaseDirectory, "localhost-key.pem");
    opt.ConfigureHttpsDefaults(opt =>
    {
        var cert = System.Security.Cryptography.X509Certificates.X509Certificate2.CreateFromPemFile(cerPemPath, cerKeyPemPath);
        opt.ServerCertificate = cert;
    });
});

Unable to launch the IIS Express Web server

如果在配置过程中有误操作,可能导致无法启动 IIS Express(本人就是),可以通过如下步骤排除问题。做完每一步都可以检查是否恢复正常。

1、检查端口是否被占用:netstat -ao | findstr <port_number_to_search_for>,结束掉PID对应的进程

2、删除 IIS Express 配置:删除C:\Users\%user%\Documents中的整个 IISExpress 文件夹,重启VS

3、删除vs配置:删除项目根目录下的隐藏文件夹 .vs 中的 config/applicationhost.config 文件(VS打开的选项卡、资源管理器中的目录树状态等会重置),重启VS

Reference


[1] Cookie 的 SameSite 属性

[2] Feature: Reject insecure SameSite=None cookies

[3] Feature: Cookies default to SameSite=Lax

[4] Work with SameSite cookies in ASP.NET Core

[5] chrome浏览器跨域Cookie的SameSite问题导致访问iframe内嵌页面异常

[6] PEM Loading in .NET Core and .NET 5

posted @ 2021-11-02 21:03  Dirt·in·firework  阅读(955)  评论(0)    收藏  举报