Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSRF Mismatch When POSTing from Ember to Sails Backend

First off, I just wanted to say that I have read through all of the other threads relating to this topic, but haven't had any luck. Here's a breakdown of the issue:

Goals

  1. Retrieve a CSRF token from Sails when the Ember Application starts
  2. Inject that CSRF token into every AJAX request that is initiated from the Ember Application

To satisfy goal 1, I created an Ember Initializer that runs when the application first boots up (if there is a better place for this, I'm totally open to suggestions). To satisfy goal 2, I retrieve the CSRF token from Sails and then attempt to use Ember.$.ajaxSetup() to ensure the CSRF token is passed either as a header (X-CSRF-Token) or parameter (_csrf). I also ensure that I'm using the withCredentials option to ensure the cookie is set. Here's the code:

// 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
};

All of this appears to work as I can see in Chrome dev tools that the CSRF token is being retrieved and when I make an AJAX request, I see the data appended to the POST data or added as a header (tried both options). Here's the code I'm running and all of the associated headers:

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

Request Headers

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

Form Data

_csrf:yP7GDiU2-YGmLBfBvQtMPT3-hRpnfK0x-AfA
email:[email protected]
password:q1w2e3r4

Response Headers

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

As you can see from the Response headers, I end up receiving a 403 Forbidden - CSRF Mismatch from Sails. Now, here's where it gets a little weird: first, I'm able to run this just fine with Postman. I retrieve a token and then post that token along with the data to the /auth/register url and it works as expected.

I'm also tried removing the initializer and running the following code:

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!');
  });
});

This works. However, at this point, I'm at somewhat of a loss as to what the issue actually is. Appreciate any help I can get.

Thanks in advance! James

like image 213
jdixon04 Avatar asked Jul 09 '15 08:07

jdixon04


People also ask

How to get CSRF token from server?

To fetch a CRSF token, the app must send a request header called X-CSRF-Token with the value fetch in this call. The server generates a token, stores it in the user's session table, and sends the value in the X-CSRF-Token HTTP response header.


2 Answers

@jdixon04, Can you try URL-encoding the CSRF token before sending it through POST? The token mismatch will occur if the token is getting altered from the original.

I found this issue in Github: https://github.com/balderdashy/sails/issues/2266.

I hope this will solve your issue. Do try it and let me know if it works. Thanks.

like image 171
phkavitha Avatar answered Sep 24 '22 23:09

phkavitha


@jdixon04, got here from your post on my github issue. Actually, isn't the CSRF token going to change at each request made to the server? Then you approach to fix the token when the frontend load cannot cope with this, you may have to fetch the token before each request and use ajaxPrefilter to pass it to the request.

Is that actually related to ember-data-sails? It seems to me you're doing pure ajax here! If you look in my config, you'll realise that pure ajax calls (for authentication as well) are exempted from csrf as I could not make it work as I wished :\ .

like image 20
tibotiber Avatar answered Sep 21 '22 23:09

tibotiber