From c348d740d4c5e3e738694bf85c42ec0a04347945 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Mon, 7 Nov 2022 18:22:47 +0100 Subject: [PATCH] fix --- spec/vulnerabilities.spec.js | 38 ++++++++++++++++++++++++++++++++++++ src/Routers/FilesRouter.js | 18 +++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 02a4ff5433..3b0eab0785 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -279,6 +279,44 @@ describe('Vulnerabilities', () => { expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); expect(text.error).toBe('Prohibited keyword in request data: {"value":"aValue[123]*"}.'); }); + + it('denies BSON type code data in file metadata', async () => { + const str = 'Hello World!'; + const data = []; + for (let i = 0; i < str.length; i++) { + data.push(str.charCodeAt(i)); + } + const file = new Parse.File('hello.txt', data, 'text/plain'); + file.addMetadata('obj', { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }); + await expectAsync(file.save()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.` + ) + ); + }); + + it('denies BSON type code data in file tags', async () => { + const str = 'Hello World!'; + const data = []; + for (let i = 0; i < str.length; i++) { + data.push(str.charCodeAt(i)); + } + const file = new Parse.File('hello.txt', data, 'text/plain'); + file.addTag('obj', { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }); + await expectAsync(file.save()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.` + ) + ); + }); }); describe('Ignore non-matches', () => { diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index f8f25475a7..08576de5e7 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -7,6 +7,7 @@ import mime from 'mime'; import logger from '../logger'; const triggers = require('../triggers'); const http = require('http'); +const Utils = require('../Utils'); const downloadFileFromURI = uri => { return new Promise((res, rej) => { @@ -140,6 +141,23 @@ export class FilesRouter { const base64 = req.body.toString('base64'); const file = new Parse.File(filename, { base64 }, contentType); const { metadata = {}, tags = {} } = req.fileData || {}; + if (req.config && req.config.requestKeywordDenylist) { + // Scan request data for denied keywords + for (const keyword of req.config.requestKeywordDenylist) { + const match = + Utils.objectContainsKeyValue(metadata, keyword.key, keyword.value) || + Utils.objectContainsKeyValue(tags, keyword.key, keyword.value); + if (match) { + next( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ) + ); + return; + } + } + } file.setTags(tags); file.setMetadata(metadata); const fileSize = Buffer.byteLength(req.body);