From 36763c2a770122687ce784df88e5a643696340b4 Mon Sep 17 00:00:00 2001 From: Bobby Wibowo Date: Tue, 22 Oct 2019 10:52:52 +0700 Subject: [PATCH] Security fix Replaced all instances of DB .whereRaw with their much safer equivalent methods. All previous usages of .whereRaw were vulnerable to SQL injections, cause we were passing the data directly. Fortunately, they were only used in API routes that required staff (moderators included) accounts. --- Updated dependency: helmet: 3.21.1 -> 3.21.2 --- controllers/uploadController.js | 41 +++++++++++++---------------- controllers/utilsController.js | 10 +++++-- package.json | 2 +- yarn.lock | 46 ++++++++++++++++----------------- 4 files changed, 50 insertions(+), 49 deletions(-) diff --git a/controllers/uploadController.js b/controllers/uploadController.js index 2b75927..e615e1b 100644 --- a/controllers/uploadController.js +++ b/controllers/uploadController.js @@ -766,34 +766,29 @@ self.list = async (req, res) => { } function filter () { - if (req.params.id !== undefined) { + if (req.params.id !== undefined) this.where('albumid', req.params.id) - } else if (!all) { + else if (!all) this.where('userid', user.id) - } else { + else // Fisrt, look for uploads matching ANY of the supplied 'user' OR 'ip' filters // Then, refine the matches using the supplied 'name' filters - const raw = [] - const source = [] - if (_filters.uploaders.length) - source.push(`\`userid\` in (${_filters.uploaders.map(v => `'${v.id}'`).join(', ')})`) - if (_filters.ips.length) - source.push(`\`ip\` in (${_filters.ips.map(v => `'${v}'`).join(', ')})`) - if (_filters.flags.nouser) - source.push('(`userid` is null or \'\')') - if (_filters.flags.noip) - source.push('(`ip` is null or \'\')') - if (source.length) - raw.push(`(${source.join(' or ')})`) - if (_filters.names.length) - raw.push(`(${_filters.names.map(v => { - if (v.includes('*')) - return `\`name\` like '${v.replace(/\*/g, '%')}'` + this.where(function () { + if (_filters.uploaders.length) + this.orWhereIn('userid', _filters.uploaders.map(v => v.id)) + if (_filters.ips.length) + this.orWhereIn('ip', _filters.ips) + if (_filters.flags.nouser) + this.orWhereNull('userid') + if (_filters.flags.noip) + this.orWhereNull('ip') + }).andWhere(function () { + for (const name of _filters.names) + if (name.includes('*')) + this.orWhere('name', 'like', name.replace(/\*/g, '%')) else - return `\`name\` = '${v}'` - }).join(' or ')})`) - this.whereRaw(raw.join(' and ')) - } + this.orWhere('name', name) + }) } // Query uploads count for pagination diff --git a/controllers/utilsController.js b/controllers/utilsController.js index 49cd50a..1b592bb 100644 --- a/controllers/utilsController.js +++ b/controllers/utilsController.js @@ -704,12 +704,18 @@ self.stats = async (req, res, next) => { } stats.uploads.images = await db.table('files') - .whereRaw(self.imageExts.map(ext => `\`name\` like '%${ext}'`).join(' or ')) + .where(function () { + for (const ext of self.imageExts) + this.orWhere('name', 'like', `%${ext}`) + }) .count('id as count') .then(rows => rows[0].count) stats.uploads.videos = await db.table('files') - .whereRaw(self.videoExts.map(ext => `\`name\` like '%${ext}'`).join(' or ')) + .where(function () { + for (const ext of self.videoExts) + this.orWhere('name', 'like', `%${ext}`) + }) .count('id as count') .then(rows => rows[0].count) diff --git a/package.json b/package.json index de49d9c..b6453fd 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "express": "^4.17.1", "express-rate-limit": "^5.0.0", "fluent-ffmpeg": "^2.1.2", - "helmet": "^3.21.1", + "helmet": "^3.21.2", "jszip": "^3.2.2", "knex": "^0.19.5", "multer": "^1.4.2", diff --git a/yarn.lock b/yarn.lock index 3522ba9..eb03afc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -203,9 +203,9 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "12.11.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.1.tgz#1fd7b821f798b7fa29f667a1be8f3442bb8922a3" - integrity sha512-TJtwsqZ39pqcljJpajeoofYRfeZ7/I/OMUQ5pR4q5wOKf2ocrUvBAZUMhWsOvKx3dVc/aaV5GluBivt0sWqA5A== + version "12.11.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.2.tgz#75ba3beda30d690b89a5089ca1c6e8e386150b76" + integrity sha512-dsfE4BHJkLQW+reOS6b17xhZ/6FB1rB8eRRvO08nn5o+voxf3i74tuyFWNH6djdfgX7Sm5s6LD8t6mJug4dpDw== "@types/q@^1.5.1": version "1.5.2" @@ -740,7 +740,7 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -bowser@^2.6.1: +bowser@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.7.0.tgz#96eab1fa07fab08c1ec4c75977a7c8ddf8e0fe1f" integrity sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w== @@ -1817,9 +1817,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.284: - version "1.3.289" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.289.tgz#1f85add5d7086ce95d9361348c26aa9de5779906" - integrity sha512-39GEOWgTxtMDk/WjIQLg4W/l1s4FZdiMCqUBLjd92tAXsBPDFLwuwCba5OGhuTdVYm6E128TZIqSnMpeocUlCQ== + version "1.3.290" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.290.tgz#a3f345abe4f1fb0a2fedf51193f4f4489bb94a82" + integrity sha512-pkKffog2KZ5PPcC8ITNXDpucznLFVVLUS2Us0tBF0Qy9114vzDpgWntvFNE1uYEmMUIrWGFu4rDMHwgQAbNYyQ== emoji-regex@^7.0.1: version "7.0.3" @@ -2663,9 +2663,9 @@ glob-watcher@^5.0.3: object.defaults "^1.1.0" glob@^7.1.1, glob@^7.1.3: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + version "7.1.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" + integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3008,20 +3008,20 @@ helmet-crossdomain@0.4.0: resolved "https://registry.yarnpkg.com/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz#5f1fe5a836d0325f1da0a78eaa5fd8429078894e" integrity sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA== -helmet-csp@2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.9.2.tgz#bec0adaf370b0f2e77267c9d8b6e33b34159c1e5" - integrity sha512-Lt5WqNfbNjEJ6ysD4UNpVktSyjEKfU9LVJ1LaFmPfYseg/xPealPfgHhtqdAdjPDopp5zbg/VWCyp4cluMIckw== +helmet-csp@2.9.4: + version "2.9.4" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.9.4.tgz#801382bac98f2f88706dc5c89d95c7e31af3a4a9" + integrity sha512-qUgGx8+yk7Xl8XFEGI4MFu1oNmulxhQVTlV8HP8tV3tpfslCs30OZz/9uQqsWPvDISiu/NwrrCowsZBhFADYqg== dependencies: - bowser "^2.6.1" + bowser "^2.7.0" camelize "1.0.0" content-security-policy-builder "2.1.0" dasherize "2.0.0" -helmet@^3.21.1: - version "3.21.1" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.21.1.tgz#b0ab7c63fc30df2434be27e7e292a9523b3147e9" - integrity sha512-IC/54Lxvvad2YiUdgLmPlNFKLhNuG++waTF5KPYq/Feo3NNhqMFbcLAlbVkai+9q0+4uxjxGPJ9bNykG+3zZNg== +helmet@^3.21.2: + version "3.21.2" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.21.2.tgz#7e2a19d5f6d898a77b5d2858e8e4bb2cda59f19f" + integrity sha512-okUo+MeWgg00cKB8Csblu8EXgcIoDyb5ZS/3u0W4spCimeVuCUvVZ6Vj3O2VJ1Sxpyb8jCDvzu0L1KKT11pkIg== dependencies: depd "2.0.0" dns-prefetch-control "0.2.0" @@ -3030,7 +3030,7 @@ helmet@^3.21.1: feature-policy "0.3.0" frameguard "3.1.0" helmet-crossdomain "0.4.0" - helmet-csp "2.9.2" + helmet-csp "2.9.4" hide-powered-by "1.1.0" hpkp "2.0.0" hsts "2.2.0" @@ -4385,9 +4385,9 @@ nocache@2.1.0: integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== node-abi@^2.7.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.11.0.tgz#b7dce18815057544a049be5ae75cd1fdc2e9ea59" - integrity sha512-kuy/aEg75u40v378WRllQ4ZexaXJiCvB68D2scDXclp/I4cRq6togpbOoKhmN07tns9Zldu51NNERo0wehfX9g== + version "2.12.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.12.0.tgz#40e9cfabdda1837863fa825e7dfa0b15686adf6f" + integrity sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw== dependencies: semver "^5.4.1"