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
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
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);
}
})());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With