csrf token using
Asked Answered
A

2

6

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

Adar answered 23/5, 2012 at 12:20 Comment(0)
J
9

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

Juttajutty answered 24/5, 2012 at 8:12 Comment(5)
Yes I know this, but I want to know what is better to use: a header x-csrf-token or hidden field?Adar
As you can see here: github.com/senchalabs/connect/blob/master/lib/middleware/… Express checks first for the POST value, then for the query string value and then for the x-csrf-token header, so the best would be to pass a hidden _csrf field with the value.Juttajutty
I want to use csrf-token on ajax requests what is approach should I use then ?Adar
The same, there's no difference between that and a normal request with regards to csrf protection. Just use the same token as a hidden field when sending requests.Juttajutty
@Juttajutty Hey, this Full example: https://github.com/senchalabs/connect/blob/master/examples/csrf.js gives a 404Pinkard
C
3

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);
  }
})());
Coucher answered 24/5, 2012 at 11:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.