diff --git a/public/src/app.js b/public/src/app.js index 4fe7871ea7..411e5f568d 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -160,9 +160,7 @@ var socket, }; app.logout = function() { - $.post(RELATIVE_PATH + '/logout', { - _csrf: $('#csrf_token').val() - }, function() { + $.post(RELATIVE_PATH + '/logout', function() { window.location.href = RELATIVE_PATH + '/'; }); }; diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js index 37a551ffef..c91f2bf706 100644 --- a/public/src/forum/admin/categories.js +++ b/public/src/forum/admin/categories.js @@ -203,7 +203,7 @@ define('forum/admin/categories', ['uploader', 'forum/admin/iconSelect'], functio var inputEl = $(this), cid = inputEl.parents('li[data-cid]').attr('data-cid'); - uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', {cid: cid}, 0, function(imageUrlOnServer) { + uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', { cid: cid }, 0, function(imageUrlOnServer) { inputEl.val(imageUrlOnServer); var previewBox = inputEl.parents('li[data-cid]').find('.preview-box'); previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')') diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index 5cda6ed0ee..01e3f8ddd8 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -17,9 +17,7 @@ define('forum/admin/index', ['semver'], function(semver) { }, 3000); $('#logout-link').on('click', function() { - $.post(RELATIVE_PATH + '/logout', { - _csrf: $('#csrf_token').val() - }, function() { + $.post(RELATIVE_PATH + '/logout', function() { window.location.href = RELATIVE_PATH + '/'; }); }); diff --git a/public/src/modules/composer/uploads.js b/public/src/modules/composer/uploads.js index 008970a3ca..54822aa681 100644 --- a/public/src/modules/composer/uploads.js +++ b/public/src/modules/composer/uploads.js @@ -235,10 +235,10 @@ define('composer/uploads', ['composer/preview'], function(preview) { textarea.val(current.replace(re, filename + '](' + text + ')')); } - $(this).find('#postUploadCsrf').val($('#csrf_token').val()); + $(this).find('#postUploadCsrf').val($('#csrf').attr('data-csrf')); if (formData) { - formData.append('_csrf', $('#csrf_token').val()); + formData.append('_csrf', $('#csrf').attr('data-csrf')); } uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || []; @@ -291,7 +291,7 @@ define('composer/uploads', ['composer/preview'], function(preview) { thumbForm.attr('action', params.route); thumbForm.off('submit').submit(function() { - var csrf = $('#csrf_token').val(); + var csrf = $('#csrf').attr('data-csrf'); $(this).find('#thumbUploadCsrf').val(csrf); if(formData) { diff --git a/public/src/modules/uploader.js b/public/src/modules/uploader.js index 64403f52fe..e44d59d4e2 100644 --- a/public/src/modules/uploader.js +++ b/public/src/modules/uploader.js @@ -19,6 +19,7 @@ define('uploader', function() { uploadForm[0].reset(); uploadForm.attr('action', route); uploadForm.find('#params').val(JSON.stringify(params)); + uploadForm.find('#csrfToken').val($('#csrf').attr('data-csrf')); if(fileSize) { uploadForm.find('#upload-file-size').html(fileSize); @@ -58,9 +59,6 @@ define('uploader', function() { return false; } - $(this).find('#imageUploadCsrf').val($('#csrf_token').val()); - - $(this).ajaxSubmit({ error: function(xhr) { xhr = maybeParse(xhr); diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 1e21ecc62a..a2aa675f0c 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -337,6 +337,8 @@ accountsController.accountEdit = function(req, res, next) { return next(err); } + userData.csrf = req.csrfToken(); + res.render('account/edit', userData); }); }; diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 241afa9699..ab28005db7 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -143,7 +143,10 @@ function filterAndRenderCategories(req, res, next, active) { return active ? !category.disabled : category.disabled; }); - res.render('admin/categories', {categories: categoryData}); + res.render('admin/categories', { + categories: categoryData, + csrf: req.csrfToken() + }); }); } @@ -197,7 +200,9 @@ adminController.languages.get = function(req, res, next) { }; adminController.settings.get = function(req, res, next) { - res.render('admin/settings', {}); + res.render('admin/settings', { + 'csrf': req.csrfToken() + }); }; adminController.logger.get = function(req, res, next) { diff --git a/src/controllers/categories.js b/src/controllers/categories.js index f9039e2bd3..febaae4ba3 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -189,6 +189,7 @@ categoriesController.get = function(req, res, next) { data.currentPage = page; data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] === '1' ? true : false; + data.csrf = req.csrfToken(); // Paginator for noscript data.pages = []; diff --git a/src/controllers/index.js b/src/controllers/index.js index 29c916a1cf..872eedd9d8 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -142,7 +142,7 @@ Controllers.login = function(req, res, next) { data.alternate_logins = num_strategies > 0; data.authentication = login_strategies; - data.token = res.locals.csrf_token; + data.token = req.csrfToken(); data.showResetLink = emailersPresent; data.allowLocalLogin = meta.config.allowLocalLogin === undefined || parseInt(meta.config.allowLocalLogin, 10) === 1; data.allowRegistration = meta.config.allowRegistration; @@ -171,7 +171,7 @@ Controllers.register = function(req, res, next) { data.authentication = login_strategies; - data.token = res.locals.csrf_token; + data.token = req.csrfToken(); data.minimumUsernameLength = meta.config.minimumUsernameLength; data.maximumUsernameLength = meta.config.maximumUsernameLength; data.minimumPasswordLength = meta.config.minimumPasswordLength; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index bb772d1dac..d0857b862a 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -198,6 +198,7 @@ topicsController.get = function(req, res, next) { data['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; + data.csrf = req.csrfToken(); var topic_url = tid + (req.params.slug ? '/' + req.params.slug : ''); var queryString = qs.stringify(req.query); diff --git a/src/middleware/admin.js b/src/middleware/admin.js index 3cef701d08..0f7af52358 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -61,7 +61,7 @@ middleware.buildHeader = function(req, res, next) { } }, function(err, pluginData) { var data = { - csrf: res.locals.csrf_token, + csrf: req.csrfToken ? req.csrfToken() : undefined, relative_path: nconf.get('relative_path'), plugins: pluginData.custom_header.plugins, authentication: pluginData.custom_header.authentication, diff --git a/src/middleware/index.js b/src/middleware/index.js index 6a29ce37c0..986d5ffe91 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -20,7 +20,6 @@ var utils = require('./../../public/src/utils'), compression = require('compression'), favicon = require('serve-favicon'), multipart = require('connect-multiparty'), - csrf = require('csurf'), session = require('express-session'), cluster = require('cluster'), @@ -116,10 +115,8 @@ module.exports = function(app, data) { })); app.use(multipart()); - app.use(csrf()); app.use(function (req, res, next) { - res.locals.csrf_token = req.csrfToken(); res.setHeader('X-Powered-By', 'NodeBB'); res.setHeader('X-Frame-Options', 'SAMEORIGIN'); diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index aec822d3a5..806be9d50b 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -16,6 +16,7 @@ var app, topics = require('./../topics'), messaging = require('../messaging'), ensureLoggedIn = require('connect-ensure-login'), + csrf = require('csurf'), controllers = { api: require('./../controllers/api') @@ -33,6 +34,8 @@ middleware.authenticate = function(req, res, next) { } }; +middleware.requireCSRF = csrf(); + middleware.ensureLoggedIn = ensureLoggedIn.ensureLoggedIn(); middleware.updateLastOnlineTime = function(req, res, next) { @@ -278,7 +281,7 @@ middleware.renderHeader = function(req, res, callback) { 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', 'brand:logo': meta.config['brand:logo'] || '', 'brand:logo:display': meta.config['brand:logo']?'':'hide', - csrf: res.locals.csrf_token, + csrf: req.csrfToken ? req.csrfToken() : undefined, navigation: custom_header.navigation, allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1, searchEnabled: plugins.hasListeners('filter:search.query') diff --git a/src/routes/admin.js b/src/routes/admin.js index 77dc3cc31a..c18cc8665c 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -9,8 +9,8 @@ function mainRoutes(app, middleware, controllers) { app.get('/admin/plugins', middleware.admin.buildHeader, controllers.admin.plugins.get); app.get('/api/admin/plugins', controllers.admin.plugins.get); - app.get('/admin/settings', middleware.admin.buildHeader, controllers.admin.settings.get); - app.get('/api/admin/settings', controllers.admin.settings.get); + app.get('/admin/settings', middleware.requireCSRF, middleware.admin.buildHeader, controllers.admin.settings.get); + app.get('/api/admin/settings', middleware.requireCSRF, controllers.admin.settings.get); app.get('/admin/themes', middleware.admin.buildHeader, controllers.admin.themes.get); app.get('/api/admin/themes', controllers.admin.themes.get); @@ -43,11 +43,11 @@ function userRoutes(app, middleware, controllers) { } function forumRoutes(app, middleware, controllers) { - app.get('/admin/categories/active', middleware.admin.buildHeader, controllers.admin.categories.active); - app.get('/api/admin/categories/active', controllers.admin.categories.active); + app.get('/admin/categories/active', middleware.requireCSRF, middleware.admin.buildHeader, controllers.admin.categories.active); + app.get('/api/admin/categories/active', middleware.requireCSRF, controllers.admin.categories.active); - app.get('/admin/categories/disabled', middleware.admin.buildHeader, controllers.admin.categories.disabled); - app.get('/api/admin/categories/disabled', controllers.admin.categories.disabled); + app.get('/admin/categories/disabled', middleware.requireCSRF, middleware.admin.buildHeader, controllers.admin.categories.disabled); + app.get('/api/admin/categories/disabled', middleware.requireCSRF, controllers.admin.categories.disabled); app.get('/admin/tags', middleware.admin.buildHeader, controllers.admin.tags.get); app.get('/api/admin/tags', controllers.admin.tags.get); @@ -57,10 +57,10 @@ function apiRoutes(app, middleware, controllers) { // todo, needs to be in api namespace app.get('/admin/users/csv', middleware.authenticate, controllers.admin.users.getCSV); - app.post('/admin/category/uploadpicture', middleware.authenticate, controllers.admin.uploads.uploadCategoryPicture); - app.post('/admin/uploadfavicon', middleware.authenticate, controllers.admin.uploads.uploadFavicon); - app.post('/admin/uploadlogo', middleware.authenticate, controllers.admin.uploads.uploadLogo); - app.post('/admin/uploadgravatardefault', middleware.authenticate, controllers.admin.uploads.uploadGravatarDefault); + app.post('/admin/category/uploadpicture', middleware.requireCSRF, middleware.authenticate, controllers.admin.uploads.uploadCategoryPicture); + app.post('/admin/uploadfavicon', middleware.requireCSRF, middleware.authenticate, controllers.admin.uploads.uploadFavicon); + app.post('/admin/uploadlogo', middleware.requireCSRF, middleware.authenticate, controllers.admin.uploads.uploadLogo); + app.post('/admin/uploadgravatardefault', middleware.requireCSRF, middleware.authenticate, controllers.admin.uploads.uploadGravatarDefault); } function miscRoutes(app, middleware, controllers) { diff --git a/src/routes/api.js b/src/routes/api.js index e152715beb..5a59a2387d 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -203,8 +203,8 @@ module.exports = function(app, middleware, controllers) { router.get('/categories/:cid/moderators', getModerators); router.get('/recent/posts/:term?', getRecentPosts); - router.post('/post/upload', uploadPost); - router.post('/topic/thumb/upload', uploadThumb); - router.post('/user/:userslug/uploadpicture', middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.uploadPicture); + router.post('/post/upload', middleware.requireCSRF, uploadPost); + router.post('/topic/thumb/upload', middleware.requireCSRF, uploadThumb); + router.post('/user/:userslug/uploadpicture', middleware.requireCSRF, middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.uploadPicture); }; diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 9b30ae08a9..6471814ad5 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -197,8 +197,8 @@ /* End backwards compatibility block */ app.post('/logout', logout); - app.post('/register', register); - app.post('/login', login); + app.post('/register', middleware.requireCSRF, register); + app.post('/login', middleware.requireCSRF, login); }); }); }; diff --git a/src/routes/index.js b/src/routes/index.js index ab72136b29..0789b2474c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -21,11 +21,11 @@ function mainRoutes(app, middleware, controllers) { app.get('/', middleware.buildHeader, controllers.home); app.get('/api', controllers.home); - app.get('/login', middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.login); - app.get('/api/login', middleware.redirectToAccountIfLoggedIn, controllers.login); + app.get('/login', middleware.requireCSRF, middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.login); + app.get('/api/login', middleware.requireCSRF, middleware.redirectToAccountIfLoggedIn, controllers.login); - app.get('/register', middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.register); - app.get('/api/register', middleware.redirectToAccountIfLoggedIn, controllers.register); + app.get('/register', middleware.requireCSRF, middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.register); + app.get('/api/register', middleware.requireCSRF, middleware.redirectToAccountIfLoggedIn, controllers.register); app.get('/confirm/:code', middleware.buildHeader, controllers.confirmEmail); app.get('/api/confirm/:code', controllers.confirmEmail); @@ -54,11 +54,11 @@ function staticRoutes(app, middleware, controllers) { function topicRoutes(app, middleware, controllers) { app.get('/api/topic/teaser/:topic_id', controllers.topics.teaser); - app.get('/topic/:topic_id/:slug/:post_index?', middleware.buildHeader, middleware.checkPostIndex, controllers.topics.get); - app.get('/api/topic/:topic_id/:slug/:post_index?', middleware.checkPostIndex, controllers.topics.get); + app.get('/topic/:topic_id/:slug/:post_index?', middleware.requireCSRF, middleware.buildHeader, middleware.checkPostIndex, controllers.topics.get); + app.get('/api/topic/:topic_id/:slug/:post_index?', middleware.requireCSRF, middleware.checkPostIndex, controllers.topics.get); - app.get('/topic/:topic_id/:slug?', middleware.buildHeader, middleware.addSlug, controllers.topics.get); - app.get('/api/topic/:topic_id/:slug?', middleware.addSlug, controllers.topics.get); + app.get('/topic/:topic_id/:slug?', middleware.requireCSRF, middleware.buildHeader, middleware.addSlug, controllers.topics.get); + app.get('/api/topic/:topic_id/:slug?', middleware.requireCSRF, middleware.addSlug, controllers.topics.get); } function tagRoutes(app, middleware, controllers) { @@ -82,11 +82,11 @@ function categoryRoutes(app, middleware, controllers) { app.get('/api/unread/total', middleware.authenticate, controllers.categories.unreadTotal); - app.get('/category/:category_id/:slug/:topic_index', middleware.buildHeader, middleware.checkTopicIndex, controllers.categories.get); - app.get('/api/category/:category_id/:slug/:topic_index', middleware.checkTopicIndex, controllers.categories.get); + app.get('/category/:category_id/:slug/:topic_index', middleware.requireCSRF, middleware.buildHeader, middleware.checkTopicIndex, controllers.categories.get); + app.get('/api/category/:category_id/:slug/:topic_index', middleware.requireCSRF, middleware.checkTopicIndex, controllers.categories.get); - app.get('/category/:category_id/:slug?', middleware.buildHeader, middleware.addSlug, controllers.categories.get); - app.get('/api/category/:category_id/:slug?', controllers.categories.get); + app.get('/category/:category_id/:slug?', middleware.requireCSRF, middleware.buildHeader, middleware.addSlug, controllers.categories.get); + app.get('/api/category/:category_id/:slug?', middleware.requireCSRF, controllers.categories.get); } function accountRoutes(app, middleware, controllers) { @@ -108,8 +108,8 @@ function accountRoutes(app, middleware, controllers) { app.get('/user/:userslug/topics', middleware.buildHeader, middleware.checkGlobalPrivacySettings, controllers.accounts.getTopics); app.get('/api/user/:userslug/topics', middleware.checkGlobalPrivacySettings, controllers.accounts.getTopics); - app.get('/user/:userslug/edit', middleware.buildHeader, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.accountEdit); - app.get('/api/user/:userslug/edit', middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.accountEdit); + app.get('/user/:userslug/edit', middleware.requireCSRF, middleware.buildHeader, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.accountEdit); + app.get('/api/user/:userslug/edit', middleware.requireCSRF, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.accountEdit); app.get('/user/:userslug/settings', middleware.buildHeader, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.accountSettings); app.get('/api/user/:userslug/settings', middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, controllers.accounts.accountSettings);