CSRF 令牌与 Laravel API 不匹配,使用带有 Sticky Session 的 Digital Ocean Load Balancer
CSRF Token Mismatch with Laravel API using Digital Ocean Load Balancer with Sticky Session
我正在 Laravel 8 中从事一个项目,我现在正在测试生产服务器上的部署。我已经设置了 2 个 Digital Ocean Droplet,它们位于启用了 Sticky Session 的负载均衡器后面。我正在尝试通过具有单独 Laravel API 的 SPA 应用程序登录,因此中间件配置为 api 路由有状态 API 并执行 CSRF 验证。当我只点击一个 Droplet 并绕过负载均衡器时,这工作得很好,但是一旦负载均衡器被使用,我总是收到 419 CSRF 令牌不匹配。
我在 Google 上找到的所有内容都表明 session 需要在服务器之间共享,但我认为在这种情况下情况并非如此。我在负载均衡器中使用名为 DO-LB 的 cookie 打开了粘性 session,因此来自同一个 session 的所有请求都转到同一台服务器,并且我正在跟踪两者上的 Apache 访问日志服务器,我可以看到所有请求,例如 get-csrf 和 auth 路由(使用 Sanctum)都命中同一台服务器,所以我仍然会得到令牌不匹配。
我也在使用 cookie session driver。
更新
我发现有些奇怪,如果我将我的 DNS 指向一个单独的 droplet,我会看到 X-XSRF-TOKEN 作为请求发送 header,但是如果我将 DNS 更改为指向然后负载平衡器 X-xSRF-TOKEN 不会作为请求 header 发送。我正在使用 Axios 发送请求,但我看不到负载均衡器如何影响 Axios
更新 2
看起来当我 运行 它在本地时 XSRF-TOKEN 不是 HttpOnly cookie 但是当 运行 在生产环境中使用它时 XSRF-TOKEN 被标记为 HttpOnly 从我读到的意思是它无法从 Javascript 访问,因此 Axios 不发送它的原因。我似乎已经通过执行 Cookies.get("XSRF-TOKEN") 并打印结果来确认这一点,它在本地将令牌打印到控制台,但在生产中它是未定义的。
更新 3
我更新了我的 Apache 配置以覆盖 headers 作为删除 HttpOnly 标志的测试,这似乎已经成功了,现在我可以在登录时看到,Chrome即使我仍然收到 CSRF 令牌不匹配,也会在请求中发送 X-XSRF-TOKEN。
我已经将 chrome cookie 存储中的字符串与 X-XSRF-TOKEN 中发送的字符串进行了比较,它们都匹配,所以我不明白为什么 Laravel 不断返回我不匹配,我完全不知所措。
我想我已经解决了这个问题,如果它可以迁移到服务器故障,那么请这样做,但我认为它可以说明它是什么而不是仅仅删除它。
我在使用 cloudflare 时犯了在 DO Droplet 和 cloudflare 之间使用自签名证书的错误,并将此证书提供给了负载均衡器。尽管 DO 没有抛出任何错误,但在 Apache 日志中我注意到尽管网站加载,但当发出 API 请求时我注意到 apache 错误日志 Server name not provided via TLS extension (using default/first virtual host)
。不确定这是否是真正的原因,但让我想到问题是否是由自签名证书引起的。
我从 Cloudflare 生成了一个新的源服务器,这意味着它有一个受信任的 CA,然后将其提供给 DO 负载均衡器,问题就消失了。
我正在 Laravel 8 中从事一个项目,我现在正在测试生产服务器上的部署。我已经设置了 2 个 Digital Ocean Droplet,它们位于启用了 Sticky Session 的负载均衡器后面。我正在尝试通过具有单独 Laravel API 的 SPA 应用程序登录,因此中间件配置为 api 路由有状态 API 并执行 CSRF 验证。当我只点击一个 Droplet 并绕过负载均衡器时,这工作得很好,但是一旦负载均衡器被使用,我总是收到 419 CSRF 令牌不匹配。
我在 Google 上找到的所有内容都表明 session 需要在服务器之间共享,但我认为在这种情况下情况并非如此。我在负载均衡器中使用名为 DO-LB 的 cookie 打开了粘性 session,因此来自同一个 session 的所有请求都转到同一台服务器,并且我正在跟踪两者上的 Apache 访问日志服务器,我可以看到所有请求,例如 get-csrf 和 auth 路由(使用 Sanctum)都命中同一台服务器,所以我仍然会得到令牌不匹配。
我也在使用 cookie session driver。
更新
我发现有些奇怪,如果我将我的 DNS 指向一个单独的 droplet,我会看到 X-XSRF-TOKEN 作为请求发送 header,但是如果我将 DNS 更改为指向然后负载平衡器 X-xSRF-TOKEN 不会作为请求 header 发送。我正在使用 Axios 发送请求,但我看不到负载均衡器如何影响 Axios
更新 2
看起来当我 运行 它在本地时 XSRF-TOKEN 不是 HttpOnly cookie 但是当 运行 在生产环境中使用它时 XSRF-TOKEN 被标记为 HttpOnly 从我读到的意思是它无法从 Javascript 访问,因此 Axios 不发送它的原因。我似乎已经通过执行 Cookies.get("XSRF-TOKEN") 并打印结果来确认这一点,它在本地将令牌打印到控制台,但在生产中它是未定义的。
更新 3
我更新了我的 Apache 配置以覆盖 headers 作为删除 HttpOnly 标志的测试,这似乎已经成功了,现在我可以在登录时看到,Chrome即使我仍然收到 CSRF 令牌不匹配,也会在请求中发送 X-XSRF-TOKEN。
我已经将 chrome cookie 存储中的字符串与 X-XSRF-TOKEN 中发送的字符串进行了比较,它们都匹配,所以我不明白为什么 Laravel 不断返回我不匹配,我完全不知所措。
我想我已经解决了这个问题,如果它可以迁移到服务器故障,那么请这样做,但我认为它可以说明它是什么而不是仅仅删除它。
我在使用 cloudflare 时犯了在 DO Droplet 和 cloudflare 之间使用自签名证书的错误,并将此证书提供给了负载均衡器。尽管 DO 没有抛出任何错误,但在 Apache 日志中我注意到尽管网站加载,但当发出 API 请求时我注意到 apache 错误日志 Server name not provided via TLS extension (using default/first virtual host)
。不确定这是否是真正的原因,但让我想到问题是否是由自签名证书引起的。
我从 Cloudflare 生成了一个新的源服务器,这意味着它有一个受信任的 CA,然后将其提供给 DO 负载均衡器,问题就消失了。