From 8abf8a8b6815735b5b084f494e850069af1b6426 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 4 Apr 2016 15:44:44 -0700 Subject: [PATCH] querystring: allow querystring parse to handle __proto__ Per #5642, using querystring.parse to parse 'a=b&__proto__=1' causes the `__proto__` to be swallowed and ignored. This works around the limitation by temporarily setting the prototype of the parsed obj to null during the parse, then setting it back before returning. Fixes: https://github.com/nodejs/node/issues/5642 --- .../querystring/querystring-parse-proto.js | 25 +++++++++++++++++++ lib/querystring.js | 8 +++--- test/parallel/test-querystring-proto.js | 13 ++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 benchmark/querystring/querystring-parse-proto.js create mode 100644 test/parallel/test-querystring-proto.js diff --git a/benchmark/querystring/querystring-parse-proto.js b/benchmark/querystring/querystring-parse-proto.js new file mode 100644 index 00000000000000..aaf9cfa97946f9 --- /dev/null +++ b/benchmark/querystring/querystring-parse-proto.js @@ -0,0 +1,25 @@ +'use strict'; +var common = require('../common.js'); +var querystring = require('querystring'); +var v8 = require('v8'); + +var bench = common.createBenchmark(main, { + n: [1e6], +}); + +function main(conf) { + var n = conf.n | 0; + + const input = 'a=b&__proto__=1'; + + v8.setFlagsFromString('--allow_natives_syntax'); + querystring.parse(input); + eval('%OptimizeFunctionOnNextCall(querystring.parse)'); + querystring.parse(input); + + var i; + bench.start(); + for (i = 0; i < n; i += 1) + querystring.parse(input); + bench.end(n); +} diff --git a/lib/querystring.js b/lib/querystring.js index ad1b5861a0f063..e628a626315b15 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -212,12 +212,13 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { sep = sep || '&'; eq = eq || '='; - const obj = {}; - if (typeof qs !== 'string' || qs.length === 0) { - return obj; + return {}; } + var obj = {}; + Object.setPrototypeOf(obj, null); + if (typeof sep !== 'string') sep += ''; @@ -387,6 +388,7 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { } } + Object.setPrototypeOf(obj, Object.prototype); return obj; }; diff --git a/test/parallel/test-querystring-proto.js b/test/parallel/test-querystring-proto.js new file mode 100644 index 00000000000000..0695a30d2f6050 --- /dev/null +++ b/test/parallel/test-querystring-proto.js @@ -0,0 +1,13 @@ +/* eslint-disable no-proto */ +'use strict'; + +require('../common'); +const assert = require('assert'); +const qs = require('querystring'); + +const obj = qs.parse('a=b&__proto__=1'); + +assert.equal(obj.a, 'b'); +assert.equal(obj.__proto__, 1); +assert(typeof Object.getPrototypeOf(obj) === 'object'); +assert.strictEqual(Object.getPrototypeOf(obj), Object.prototype);