Laravel CSRF保护下的JQuery AJAX跨站点请求

时间:2015-07-16 14:54:40

标签: php jquery ajax laravel csrf

我正在使用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令牌(POST,PUT ......将修改资源)。

就我而言,我必须在 api.test.com 而不是 test.com 上生成 csrf_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);
}

$ token ,我 POST '与...不同( $ request-> session() - > token())。

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

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

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

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

谢谢, Micooz

3 个答案:

答案 0 :(得分:3)

感谢您回答我的问题。我已经考虑禁用对某些URI的CSRF保护,但我不想承担这些风险。

我的问题的关键点是$ .ajax在请求之前忘记携带cookie,结果令牌验证失败。

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

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

和Nginx conf:

  add_header Access-Control-Allow-Credentials true;
顺便说一句,没有必要在数据中包含令牌:{}(表单)。

所有问题都已解决,对我来说非常有效。

答案 1 :(得分:0)

Laravel希望令牌作为数据变量(包含在您的字段中),var的名称需要_token尝试更改它。

另一种解决方案是将数据中的令牌包含在标题中。

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

答案 2 :(得分:-1)

您可以关注此网址

http://laravel.io/forum/11-14-2014-disabling-the-csrf-middleware-in-laravel-5

在此链接中,您需要将VerifyCsrfToken类包含在新的一个类中,您可以在其中指定不使用csrf_token的操作