Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to protect against CSRF when using Backbone.js to post data?

Backbone.js handles posting data to server under the hood, so there is no easy way to insert a CSRF token in the payload. How can I protect my site against CSRF in this situation?

In this SO answer: https://stackoverflow.com/a/10386412/954376, the suggestion is to verify the x-Requested-By header to be XMLHTTPRequest. Is this enough to block all CSRF attempts?

In Django docs, the suggestion is to add CSRF token in another custom header in every AJAX request: https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax. Is this necessary?

I understand if the attack uses hidden form, I am safe by just assuring the request is from XMLHTTPRequest. But is there any CSRF attack tricks that can forge the header?

like image 734
NeoWang Avatar asked Aug 08 '13 11:08

NeoWang


3 Answers

Setting a global CSRF-token for all jQuery.ajax calls:

$(function(){ 
  $.ajaxSetup({
    headers: {'X-CSRFToken': CSRF_TOKEN}
  });
})

Setting the token just for Backbone by overriding Backbone.sync:

var oldSync = Backbone.sync;
Backbone.sync = function(method, model, options){
  options.beforeSend = function(xhr){
    xhr.setRequestHeader('X-CSRFToken', CSRF_TOKEN);
  };
  return oldSync(method, model, options);
};

EDIT: Fixed a typo Kadam points at in comments

like image 159
Pasi Jokinen Avatar answered Nov 11 '22 07:11

Pasi Jokinen


You can use a prefilter to add the token to all requests:

$.ajaxPrefilter(function(opts) {
    if (opts.data) {
        opts.data += "&";
    }
    opts.data += "csrfToken=" + token;
});

You may need to add additional logic if you don't always send the token.

like image 35
Esailija Avatar answered Nov 11 '22 07:11

Esailija


Here's an updated version, based in Django 1.7 (using the jQuery cookie plugin)

oldSync = Backbone.sync
Backbone.sync = (method, model, options) ->

    csrfSafeMethod = (method) ->
        # these HTTP methods do not require CSRF protection
        /^(GET|HEAD|OPTIONS|TRACE)$/.test method

    options.beforeSend = (xhr, settings) ->
        if !csrfSafeMethod(settings.type) and !@crossDomain
            xhr.setRequestHeader 'X-CSRFToken', $.cookie('csrftoken')
        return
    oldSync method, model, options
like image 39
Akhorus Avatar answered Nov 11 '22 08:11

Akhorus