Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

csrf token using

I'm interested in a protecting of my web application by using generation a csrf token. My question is how do I need to send that token back to a server: using query param or http header x-csrf-token ?

And what is the difference

like image 290
Erik Avatar asked May 23 '12 12:05

Erik


2 Answers

Since you're using Express, you can use its CSRF middleware (by Connect): http://www.senchalabs.org/connect/csrf.html

You can checkout the commented source here: https://github.com/senchalabs/connect/blob/master/lib/middleware/csrf.js

All you need to do is to include that middleware and then in your POST forms (or PUT etc whatever request that mutates state) set the variable _csrf to have the value req.session._csrf.

Check example here: https://github.com/senchalabs/connect/blob/master/examples/csrf.js

UPDATE

Since Connect 2.9.0 you must use req.csrfToken() instead of req.session._csrf

Full example: https://github.com/senchalabs/connect/blob/master/examples/csrf.js

Commit: https://github.com/senchalabs/connect/commit/70973b24eb1abe13b2da4f45c1edbb78c611d250

UPDATE2

The connect middleware was split into different modules (and associated repos), you can find them all (including the CSRF one) here: https://github.com/senchalabs/connect#middleware

like image 98
alessioalex Avatar answered Sep 26 '22 01:09

alessioalex


From my point of view, you should use the csrf POST parameter when submitting forms, in an hidden field. This is the only way to go.

But for AJAX requests, I would strongly advise you to use the X-CSRF-Token header instead. Mainly because, if done correctly, it will save you the hassle of remembering to add the token for each POST request. Or, when using libraries such as jQuery Form, adding additional POST parameters at submit time can become hackish.

For example, if you use jQuery for your AJAX requests, it provides you with a hook you can use to set the X-CSRF-Token automatically and transparently before the request is made. Thus, very little client-side code modification is required. And you skyrocket your code's awesomeness.

--

An example implementation, which I use successfully on virtually all of my projects, based on Django's one, would be:

jQuery(document).ajaxSend(function(event, xhr, settings) {

  function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) == (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  function sameOrigin(url) {
    // url could be relative or scheme relative or absolute
    var host = document.location.host; // host + port
    var protocol = document.location.protocol;
    var sr_origin = '//' + host;
    var origin = protocol + sr_origin;
    // Allow absolute or scheme relative URLs to same origin
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
           (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
           // or any other URL that isn't scheme relative or absolute i.e relative.
           !(/^(\/\/|http:|https:).*/.test(url));
  }

  function safeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
    xhr.setRequestHeader("X-CSRFToken", getCookie('csrf.token'));
  }
});

On the server-side, you'd just need to set a cookie containing the CSRF token so it is easy for the client to get the token. I replaced the app.use(express.csrf()) with:

app.use((function(options) {

  var csrf = express.csrf(options);

  return function(req, res, next) {

    function onCsrfCalled() {
      var token = req.session._csrf;
      var cookie = req.cookies['csrf.token'];

      // Define a cookie if not present
      if(token && cookie !== token) {
        res.cookie('csrf.token', token);
      }

      // Define vary header
      res.header('Vary', 'Cookie');

      next();
    }

    csrf(req, res, onCsrfCalled);
  }
})());
like image 45
Pierre Avatar answered Sep 27 '22 01:09

Pierre