Skip to content

querystring: allow querystring parse to handle __proto__ - #6044

Closed
jasnell wants to merge 1 commit into
nodejs:masterfrom
jasnell:querystring-proto
Closed

querystring: allow querystring parse to handle __proto__#6044
jasnell wants to merge 1 commit into
nodejs:masterfrom
jasnell:querystring-proto

Conversation

@jasnell

Copy link
Copy Markdown
Member

Pull Request check-list

  • Does make -j8 test (UNIX) or vcbuild test nosign (Windows) pass with
    this change (including linting)?
  • Is the commit message formatted according to [CONTRIBUTING.md][0]?
  • If this change fixes a bug (or a performance problem), is a regression
    test (or a benchmark) included?

Affected core subsystem(s)

querystring

Description of change

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.

The rest of the existing implementation remains the same.

Fixes: #5642

/cc @mscdex@WebReflection

@jasnelljasnell added the querystring Issues and PRs related to the built-in querystring module. label Apr 4, 2016
@jasnelljasnell changed the title querystring: all querystring parse to handle __proto__querystring: allow querystring parse to handle __proto__Apr 4, 2016
@jasnell
jasnellforce-pushed the querystring-proto branch 2 times, most recently from f9b4060 to e0fb8ddCompareApril 4, 2016 22:53
@mscdex

Copy link
Copy Markdown
Contributor

If this change is going to be made, wouldn't it be simpler to just use Object.create(null) instead of {} for obj? What is the performance difference if there is any?

@jasnell

Copy link
Copy Markdown
MemberAuthor

Interesting... using Object.create(null) gives a slight performance edge in a simple benchmark:

'use strict';varcommon=require('../common.js');varquerystring=require('querystring');varv8=require('v8');varbench=common.createBenchmark(main,{n: [1e6],});functionmain(conf){varn=conf.n|0;constinput='a=b&__proto__=1';v8.setFlagsFromString('--allow_natives_syntax');querystring.parse(input);eval('%OptimizeFunctionOnNextCall(querystring.parse)');querystring.parse(input);vari;bench.start();for(i=0;i<n;i+=1)querystring.parse(input);bench.end(n);}

@jasnell

Copy link
Copy Markdown
MemberAuthor

@mscdex ... updated to use Object.create(null).

Comment threadlib/querystring.js Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we comfortable with this inconsistency?

@mscdex

Copy link
Copy Markdown
Contributor

FWIW using Object.create(null) was already discussed in the linked issue and has its own set of performance regressions. Is this solution (out of the other suggested solutions in the linked issue) and its performance something that everyone can (mostly) agree on?

@mscdexmscdex added the semver-major PRs that contain breaking changes and should be released in the next major version. label Apr 4, 2016
@Fishrock123

Copy link
Copy Markdown
Contributor

👎 Unless we can see that Object.create(null) isn't orders of magnitude slower. :/

@mscdex

Copy link
Copy Markdown
Contributor

@Fishrock123 It still is.

@jasnell I think I may have found a solution that doesn't cause a performance regression and may even provide somewhat of a performance boost.

@jasnell

Copy link
Copy Markdown
MemberAuthor

Sigh, every time I benchmark this I'm getting different results. I'll switch it back to {} for now. What's the alternative you found @mscdex ?

Per nodejs#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: nodejs#5642
@WebReflection

Copy link
Copy Markdown
Contributor

since you never know how much optimization could be done, I'd go for:

// beginvarobj=Object.setPrototypeOf({},null);// ... rest of the code ...// endreturnObject.setPrototypeOf(obj,Object.prototype);

at least it couldn't go more compact than that, and the returned value from setPrototypeOf doens't get wasted.

Comment threadlib/querystring.js
return {};
}

var obj = {};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not Object.create(null)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, had this open for a while and GH refreshed so I just now noticed this was already discussed.

@Sinewyk

Copy link
Copy Markdown

Related: #6055

@jasnell

Copy link
Copy Markdown
MemberAuthor

Closing in favor of @mscdex's #6055

@jasnelljasnell closed this Apr 7, 2016
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

querystringIssues and PRs related to the built-in querystring module.semver-majorPRs that contain breaking changes and should be released in the next major version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

querystring module swallows __proto__ key

6 participants

@jasnell@mscdex@Fishrock123@WebReflection@Sinewyk@benjamingr