New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rest): further sanitize json parsing by rejecting prohibited keys #6676
Conversation
d48c33f
to
744aa9e
Compare
expect(() => parseJson(text)).to.throw( | ||
'JSON string cannot contain "constructor.prototype" key.', | ||
); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think string contain constructor.prototype
like:
const text = '{"x": "1", "constructor.prototype.y": {"z": 2}}'
is also a valid case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to block constructor.prototype.y
as a key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally people use JSON.stringify(someObject) to create a string. I've never seen a string with proto and constructor.prototype etc. So are you adding checks in parseJson(text) in case someone types the string completely by hand without using JSON.stringify() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emonddr This PR is to sanitize user input from API clients with bad intention to exploit the server vulnerabilities such as prototype pollution
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raymondfeng I tested the following example in chrome:
var myObj = {};
myObj.constructor.prototype.foo = "bar"
"bar"
console.log({}.foo)
VM373:1 bar
so I think pattern constructor.prototype.*
does pollute?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I believe your sanitizeJsonParse
function checks this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two different things:
myObj.constructor.prototype
// nesting properties constructor/prototyemyObj['constructor.prototype']
// a special property namedconstructor.protoyype
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, got the difference 馃憤
packages/rest/src/parse-json.ts
Outdated
if ( | ||
key === 'constructor' && | ||
value != null && | ||
Object.prototype.hasOwnProperty.call(value, 'prototype') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we check the value's field contains prototype
as well? like:
const text = '{"x": "1", "y": {"constructor": {"prototype.z": {"foo": 2}}}}';
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, only {"constructor": {"prototype": ...}}
is dangerous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, only
{"constructor": {"prototype": ...}}
is dangerous.
Why is that dangerous? If you could clarify. thanks :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yikes. The fact that it pollutes all objects after one string is parsed...wow. Thanks for the link.
@bajtos Can you review the PR? |
744aa9e
to
14ee793
Compare
14ee793
to
e3a4fab
Compare
@raymondfeng , perhaps a test where an application actually sets
with options containing the In the current test cases,
It would be nice to see export function sanitizeJsonParse(
reviver?: (key: any, value: any) => any,
prohibitedKeys?: string[],
) {
prohibitedKeys = [
'__proto__',
'constructor.prototype',
...(prohibitedKeys ?? []),
]; exercised in this complete path. Just a thought. |
4209959
to
5f7cbb2
Compare
- reject `__proto__` and `constructor.prototype` by default - allow validation options to provide additional prohibitedKeys Signed-off-by: Raymond Feng <enjoyjava@gmail.com>
5f7cbb2
to
ae0b993
Compare
throw new Error('JSON string cannot contain "__proto__" key.'); | ||
if (key === '__proto__') { | ||
// Reject `__proto__` | ||
throw new Error(`JSON string cannot contain "${key}" key.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it okay throws an Error? i think this returns a 500 error and could stop the application may be should throw a 422 (Unprocessable Entity)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://github.com/strongloop/loopback-next/blob/ae0b9936e7eadbf6f0ee7c72e1a04b87dda7c2c5/examples/todo/src/__tests__/acceptance/todo.acceptance.ts#L183. JSON parsing errors are wrapped into 400
.
Personally, I would prefer to leverage an existing solution from Node.js/npm ecosystem instead of inventing our own solution. Few packages to consider: |
I would love to use https://github.com/fastify/secure-json-parse but it does not allow us to filter out keys such as |
@bajtos Since it's a security concern, we should probably land and release the PR for now and improve it overtime. |
Signed-off-by: Raymond Feng enjoyjava@gmail.com
Checklist
npm test
passes on your machinepackages/cli
were updatedexamples/*
were updated馃憠 Check out how to submit a PR 馃憟