From 00193858a02baf3457bc20d67bb86d72b2ea94ee Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Fri, 30 Apr 2021 08:42:26 +0200 Subject: [PATCH] fix: generate csrf tokens on server not client (#41908) Co-authored-by: Mrugesh Mohapatra <1884376+raisedadead@users.noreply.github.com> --- api-server/src/server/middlewares/csurf.js | 21 +++++++++----- client/package-lock.json | 33 ---------------------- client/package.json | 1 - client/src/utils/ajax.js | 14 ++++----- 4 files changed, 20 insertions(+), 49 deletions(-) diff --git a/api-server/src/server/middlewares/csurf.js b/api-server/src/server/middlewares/csurf.js index ebce81abc3..600955add4 100644 --- a/api-server/src/server/middlewares/csurf.js +++ b/api-server/src/server/middlewares/csurf.js @@ -1,12 +1,14 @@ import csurf from 'csurf'; +const opts = { + domain: process.env.COOKIE_DOMAIN || 'localhost', + sameSite: 'strict', + secure: process.env.FREECODECAMP_NODE_ENV === 'production' +}; + export default function getCsurf() { const protection = csurf({ - cookie: { - domain: process.env.COOKIE_DOMAIN || 'localhost', - sameSite: 'strict', - secure: process.env.FREECODECAMP_NODE_ENV === 'production' - } + cookie: opts }); return function csrf(req, res, next) { const { path } = req; @@ -16,8 +18,13 @@ export default function getCsurf() { path ) ) { - return next(); + next(); + } else { + // add the middleware + protection(req, res, next); + // use the middleware to generate a token. The client sends this back via + // a header + res.cookie('csrf_token', req.csrfToken(), opts); } - return protection(req, res, next); }; } diff --git a/client/package-lock.json b/client/package-lock.json index 35ffcb8773..d5cf06d3c3 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -6712,16 +6712,6 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, - "csrf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", - "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", - "requires": { - "rndm": "1.2.0", - "tsscmp": "1.0.6", - "uid-safe": "2.1.5" - } - }, "css": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", @@ -20719,11 +20709,6 @@ "ret": "~0.1.10" } }, - "random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -22219,11 +22204,6 @@ "inherits": "^2.0.1" } }, - "rndm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", - "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" - }, "rst-selector-parser": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", @@ -24255,11 +24235,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" - }, "tsutils": { "version": "3.19.1", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.19.1.tgz", @@ -24360,14 +24335,6 @@ "typescript-compare": "^0.0.2" } }, - "uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "requires": { - "random-bytes": "~1.0.0" - } - }, "unbox-primitive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", diff --git a/client/package.json b/client/package.json index e425d2b4d1..d75a82302b 100644 --- a/client/package.json +++ b/client/package.json @@ -62,7 +62,6 @@ "buffer": "6.0.3", "chai": "4.3.4", "crypto-browserify": "3.12.0", - "csrf": "3.1.0", "date-fns": "2.21.1", "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.6", diff --git a/client/src/utils/ajax.js b/client/src/utils/ajax.js index 1cb9e50172..8efac8cec1 100644 --- a/client/src/utils/ajax.js +++ b/client/src/utils/ajax.js @@ -1,22 +1,20 @@ import envData from '../../../config/env.json'; import axios from 'axios'; -import Tokens from 'csrf'; import cookies from 'browser-cookies'; const { apiLocation } = envData; const base = apiLocation; -const tokens = new Tokens(); axios.defaults.withCredentials = true; -// _csrf is passed to the client as a cookie. Tokens are sent back to the server -// via headers: +// CSRF-Server-Token is passed to the client as a cookie. The client must send +// this back as a header. function setCSRFTokens() { - const _csrf = typeof window !== 'undefined' && cookies.get('_csrf'); - if (!_csrf) return; - axios.defaults.headers.post['CSRF-Token'] = tokens.create(_csrf); - axios.defaults.headers.put['CSRF-Token'] = tokens.create(_csrf); + const csrfToken = typeof window !== 'undefined' && cookies.get('csrf_token'); + if (!csrfToken) return; + axios.defaults.headers.post['CSRF-Token'] = csrfToken; + axios.defaults.headers.put['CSRF-Token'] = csrfToken; } function get(path) {