diff --git a/lib/hooks/csrf/index.js b/lib/hooks/csrf/index.js index af2a0c332b..e7e0bf0748 100644 --- a/lib/hooks/csrf/index.js +++ b/lib/hooks/csrf/index.js @@ -28,14 +28,16 @@ module.exports = function(sails) { sails.config.csrf = { grantTokenViaAjax: true, protectionEnabled: true, - origin: '-' + origin: '-', + routesDisabled: '-' }; } else if (sails.config.csrf === false) { sails.config.csrf = { grantTokenViaAjax: false, protectionEnabled: false, - origin: '-' + origin: '-', + routesDisabled: '-' }; } // If user provides ANY object (including empty object), enable all default @@ -44,7 +46,8 @@ module.exports = function(sails) { _.defaults(typeof sails.config.csrf === 'object' ? sails.config.csrf : {}, { grantTokenViaAjax: true, protectionEnabled: true, - origin: '-' + origin: '-', + routesDisabled: '-' }); } // Add the csrfToken directly to the config'd routes, so that the CORS hook can process it @@ -63,12 +66,15 @@ module.exports = function(sails) { var connect = require('express/node_modules/connect'); return connect.csrf()(req, res, function(err) { + + var isRouteDisabled = sails.config.csrf.routesDisabled.split(',').indexOf(req.path) > -1; + if (util.isSameOrigin(req) || allowCrossOriginCSRF) { res.locals._csrf = req.csrfToken(); } else { res.locals._csrf = null; } - if (err) { + if (err && !isRouteDisabled) { // Return an Access-Control-Allow-Origin header in case this is a xdomain request if (req.headers.origin) { res.set('Access-Control-Allow-Origin', req.headers.origin); @@ -109,4 +115,4 @@ function csrfToken (req, res, next) { return res.json({ _csrf: res.locals._csrf }); -} +} \ No newline at end of file diff --git a/test/integration/hook.cors_csrf.test.js b/test/integration/hook.cors_csrf.test.js index b15e095bdb..d86f2fc9af 100644 --- a/test/integration/hook.cors_csrf.test.js +++ b/test/integration/hook.cors_csrf.test.js @@ -771,6 +771,32 @@ describe('CORS and CSRF ::', function() { }); + describe("with CSRF set to {protectionEnabled: true, routesDisabled: '/user'}", function() { + + before(function() { + fs.writeFileSync(path.resolve('../', appName, 'config/csrf.js'), "module.exports.csrf = {protectionEnabled: true, routesDisabled: '/user'};"); + }); + + it("a POST request on /user without a CSRF token should result in a 200 response", function (done) { + httpHelper.testRoute("post", 'user', function (err, response) { + if (err) return done(new Error(err)); + assert.equal(response.statusCode, 200); + done(); + }); + + }); + + it("a POST request on /test without a CSRF token should result in a 403 response", function (done) { + httpHelper.testRoute("post", 'test', function (err, response) { + if (err) return done(new Error(err)); + assert.equal(response.statusCode, 403); + done(); + }); + + }); + + }); + }); describe("CORS+CSRF ::", function () {