从Ember到Sails后端发布时CSRF不匹配

时间:2015-07-09 08:31:29

标签: javascript jquery ajax ember.js sails.js

首先,我只想说我已阅读了与此主题相关的所有其他主题,但没有任何运气。以下是该问题的细分:

目标

  1. 在Ember应用程序启动时从Sails中检索CSRF令牌
  2. 将CSRF令牌注入从Ember应用程序启动的每个AJAX请求
  3. 为了满足目标1,我创建了一个Ember初始化程序,它在应用程序首次启动时运行(如果有更好的位置,我完全愿意接受建议)。为了满足目标2,我从Sails中检索CSRF令牌,然后尝试使用Ember.$.ajaxSetup()来确保CSRF令牌作为标头(X-CSRF-Token)或参数(_csrf)传递。我还确保我使用withCredentials选项来确保设置cookie。这是代码:

    // initializers/csrf.js
    import Ember from 'ember';
    import config from '../config/environment';
    
    export function initialize() {
      Ember.$.get(config.APP.API_URL + '/csrfToken').then(function(result) {
        Ember.$.ajaxSetup({
          data: {
            '_csrf': result._csrf
          },
          xhrFields: { withCredentials: true }
        });
      }, function(error) {
        console.log(error);
      });
    }
    
    export default {
      name: 'csrf',
      initialize: initialize
    };
    

    所有这些看起来都有用,因为我在Chrome开发工具中可以看到正在检索CSRF令牌,当我发出AJAX请求时,我看到附加到POST数据的数据或添加为标题(尝试了两个选项) )。这是我正在运行的代码以及所有相关的标题:

    Ember.$.post(config.APP.API_URL + '/auth/register', {
      'email': _this.get('email'),
      'password': _this.get('password')
    }).then(function(response) {
      console.log('It worked!');
    });
    

    请求标头

    POST /auth/register HTTP/1.1
    Host: localhost:1337
    Connection: keep-alive
    Content-Length: 82
    Accept: */*
    Origin: http://localhost:4200
    CSP: active
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    DNT: 1
    Referer: http://localhost:4200/signup
    Accept-Encoding: gzip, deflate
    Accept-Language: en-US,en;q=0.8
    Cookie: sails.sid=s%3AbrABhErTY3-ytTWOKFJ2KBj7DCAzaLDc.apD60Sd%2BW85GSbTfJ7E3B2PrUwnhOsW6GlNpZTu9jFg
    

    表格数据

    _csrf:yP7GDiU2-YGmLBfBvQtMPT3-hRpnfK0x-AfA
    email:test@test.com
    password:q1w2e3r4
    

    响应标头

    HTTP/1.1 403 Forbidden
    Vary: X-HTTP-Method-Override
    Access-Control-Allow-Origin: http://localhost:4200
    Access-Control-Allow-Credentials: true
    Content-Type: text/html; charset=utf-8
    Content-Length: 13
    Date: Thu, 09 Jul 2015 08:11:34 GMT
    Connection: keep-alive
    

    从响应标头中可以看出,我最终收到来自Sails的403 Forbidden - CSRF Mismatch。现在,这里有点奇怪:首先,我能够与Postman一起运行。我检索一个令牌,然后将该令牌与数据一起发布到/auth/register网址,并按预期工作。

    我也尝试删除初始化程序并运行以下代码:

    Ember.$.ajaxSetup({
      xhrFields: { withCredentials: true }
    });
    
    Ember.$.get(config.APP.API_URL + '/csrfToken').then(function(result) {
      Ember.$.post(config.APP.API_URL + '/auth/register', {
        'email': _this.get('email'),
        'password': _this.get('password'),
        '_csrf': result._csrf
      }).then(function(response) {
        console.log('It worked!');
      });
    });
    

    这有效。然而,在这一点上,我对这个问题究竟是什么感到有些失落。感谢我能得到的任何帮助。

    提前致谢! 詹姆斯

3 个答案:

答案 0 :(得分:2)

@ jdixon04,您可以在通过POST发送之前尝试对CSRF令牌进行URL编码吗?如果令牌从原始版本更改,则会发生令牌不匹配。

我在Github中发现了这个问题:https://github.com/balderdashy/sails/issues/2266

我希望这能解决你的问题。试一试,让我知道它是否有效。感谢。

答案 1 :(得分:2)

@ jdixon04,来自your post on my github issue。实际上,在向服务器发出的每个请求中,CSRF令牌是否会发生变化?然后,当前端加载无法处理此问题时,您可以修复令牌,您可能必须在每个请求之前获取令牌并使用ajaxPrefilter将其传递给请求。

这实际上与ember-data-sails有关吗?在我看来,你在这里做纯粹的ajax!如果你查看我的配置,你会发现纯粹的ajax调用(也用于身份验证)免于csrf,因为我无法按照我的意愿使用它:\。

答案 2 :(得分:0)

像这样添加x-csrf-token标头:

Ember.$.ajaxSetup({
  headers: {
    'X-CSRF-TOKEN': result._csrf
  },
  xhrFields: { withCredentials: true }
});