我正在使用 Laravel(后端)和 ReactJS 和 JQuery(前端)构建一个类似 CMS 的 Web 应用程序。

我决定将现有的 Web API 放入一个单独的域 (api.test.com),而我的用户界面位于不同的域 (test.com) 中。

test.com 上,我向 api.test.com 发起 ajax 请求以修改服务器上的一些资源:

  $.ajax({
    url: "api.test.com",
    method: 'POST',
    data: {...}
    success: function (no) {
    // ...
    }
  });

当然,由于安全问题,这是非法的。但是,我可以配置我的 Web 服务器:

对于 Nginx:
  add_header Access-Control-Allow-Origin http://test.com;
  add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
  add_header Access-Control-Allow-Headers X-Requested-With,X-CSRF-TOKEN,X-XSRF-TOKEN;

Access-Control-Allow-Origin 问题完美解决,但是由于 Laravel 的 CSRF 保护又出现了另一个问题...

默认情况下,Laravel 需要一个包含在请求中的 CSRF token (POST、PUT...这将修改资源)。

就我而言,我必须在 api.test.com 上生成 csrf_token 而不是 test.com 因为不同的域不共享 token 。

我遵循了 Laravel 的用户指南并将这些代码添加到我的前端:
  $.ajax({
    url: "api.test.com/token", // simply return csrf_token();
    method: "GET",
    success: function (token) {
      // Now I get the token
      _token = token;
    }.bind(this)
  });

并修改之前的请求实现:
  $.ajax({
    url: "api.test.com",
    method: 'POST',
    headers: {
      "X-CSRF-TOKEN": _token // Here I passed the token
    },
    data: {...}
    success: function (no) {
    // ...
    }
  });

但是 Laravel 响应状态码为 500。然后我检查了 VerifyCsrfToken.php :
protected function tokensMatch($request)
{
    $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
    if (!$token && $header = $request->header('X-XSRF-TOKEN')) {
        $token = $this->encrypter->decrypt($header);
    }
    // Log::info($request->session()->token() . " == $token");
    return Str::equals($request->session()->token(), $token);
}

我' POST ' 的 $token 与原来的不同( $request->session()->token() )。

我发现调用 $.ajax 时服务器上的验证 token 是不同的。

我尝试将两个请求放在同一个 session 中(通过更改 cookie),但这是不可能的。

我花了很多时间来解决这个问题,但没有解决。

有任何想法或解决方案吗?

谢谢,
米酷

最佳答案

谢谢你回答我的问题。我考虑过 禁用 对某些 URI 的 CSRF 保护,但我不想冒这些风险。

我的问题的关键点是 $.ajax 在请求之前忘记携带 cookie,导致 token 验证失败。

现在我设置了 JQuery Ajax,让它在发出请求之前携带 cookie。

  $.ajaxSetup({
    xhrFields: { withCredentials: true }
  });

和 Nginx 配置:
  add_header Access-Control-Allow-Credentials true;

顺便说一句,没有必要在数据中包含 token :{}( 表单 )。

所有的问题都解决了,它对我来说完美无缺。

关于php - Laravel CSRF保护下的JQuery AJAX跨站请求,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31457719/

10-12 12:46
查看更多