-
Notifications
You must be signed in to change notification settings - Fork 731
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’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query fails with "DeserializationError: Object contains forbidden prototype property" when the response object has a "constructor" key #1408
Comments
Hello! The JSON parser aggressively blocks every object that might expose you to a prototype pollution attack. const sjson = require('secure-json-parse')
const { Client, Serializer, errors } = require('@elastic/elasticsearch')
class InsecureSerializer extends Serializer {
deserialize (json) {
let object
try {
object = sjson.parse(json, { constructorAction: 'ignore' })
} catch (err) {
throw new errors.DeserializationError(err.message, json)
}
return object
}
}
const client = new Client({
node: 'http://localhost:9200',
Serializer: InsecureSerializer
}) See secure-json-parse for all the available options. |
Thanks for your reply @delvedor. We're aware of the workaround (providing a custom serializer, although we actually went back to using the standard I've read those two links you've provided but what I think is missing here (or rather, in the original PR) is an example of how this could be an attack vector in ElasticSearch, especially when this is such an aggressive change that breaks perfectly working/valid/inocuous responses from ES (and even worse, it can randomly start happening in production at any time) and it's been made the default behaviour. This is why I personally consider it a bug, or at the very least, a breaking change (that wasn't flagged as such). The examples in those links seem to talk about specific actions (merge/clone) when dealing with arbitrary input from external sources, rather than simply parsing a response from what I imagine in most cases is a trusted internal ElasticSearch instance.
This is not an option in our case. The example my colleague @matAtWork provided was just a simple way to reproduce, but when dealing with the actual use case that broke for us (Term Vectors API) the only way to avoid it would be to prevent the word |
You a right, an example could help. Given the enormous risks that an attack like this one could expose you, we have preferred to make this option opt-out and offer the highest security level to this library's users. I'll update the documentation to make this clearer and show how to opt-out of this behavior if you can't possibly do otherwise.
I strongly recommend updating your code with the code I've posted above, as it will partly protect you against this attack but still allowing your use case. |
@delvedor - I think you have failed to understand the concept of "Separation of concerns". JSON is used in ES as a transport format - any security and resilience issues (for example fields that are sensitive or contain passwords) are not a concern of the transport, and not addressed by your library. Where are the "permitted" values documented? How does a developer know that certain data elements are "dangerous"? What about future-proofing - will more discarded values be added in the future, potentially breaking production systems in unknowable and unpredictable ways? In order to avoid a theoretical issue, you have introduced a breaking change in production systems. The issue highlighted by the links you have posted, which refer to downstream code issues - it is not the deserialziation of the object that is a risk, but what one does with those objects (eg
...works exactly as expected - the properties can be referenced exactly as defined:
The "error" you describe is to use the result of the This is a bad fix for the issue of prototype pollution and breaks perfectly legitimate code, in fact it precludes storing arbitrary data in ES which is impossible to create test cases for as the names and values are buried in a 3rd party library. It should not be a default, and since ES allows developers can specify their own Serializer classes (and JSON reviver, which is better way to implement this in any case), for those projects where this may be a concern, they can use it if they wish. Making correct ES operation dependent on the data contained is a very retrograde step. |
In fact, I note that in https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c the fix is described as a change to the However, |
Hi @matAtWork, thank you for sharing your perspective. You are right when you say that I agree that there could have been better communication around this change, and I apologize for it. The documentation will be updated to address this point, but the library default will not change, especially because there is an official way to override the default secure behavior. |
Even if I were to agree the issue is in You have fixed attempted an upstream fix. I would not, for example, suggest the way to "fix" ES security would be to junk http in favour of https, as it would break loads of installations. The correct solution to insecure connections would be to operate within a secure network/VPN or utilize https, not to unilaterally declare "http" insecure and simply remove it. I could come up with many other examples of where attempts at upstream fixes, while convenient, create endless legacy and edge cases as, to be frank, you have not "fixed" the issue. I cannot understand why you could countenance a breaking change when many, many users will have handled the issue you believe you have "fixed" in the correct place. This change should be reverted as a default - it is an on-going risk to production systems. However, in our case we use a working |
Perhaps a compromise would be to issue a warning of some description about a "Potential prototype pollution", rather than abort the operation. For example, an SQL DB that threw an exception on |
I'm not sure what you mean with "re-apply for subsequent releases", injecting a custom serializer class is part of the client's public API, and it's the recommended way to do such a thing.
It could, but the performance cost would be too high, as you must analyze the string before parsing it. As said, the client's default won't change, but we'll do a better job at documenting it and show how to change it. Thank you for your feedback!. |
I really think this is the wrong approach here, and that the potential vulnerability that tries to avoid is completely out of the scope of a client lib like this. I wonder if popular requests libraries like node-fetch or axios would throw similar errors when calling an API with |
@delvedor In all honesty, I think you've failed to objectively assess this and certainly to assess the potential impacts in the future. Do the other clients filter out these fields/data values? What about all the other clients described in https://www.elastic.co/guide/en/elasticsearch/client/index.html ? Is the JS implementation really going to fail where PHP, Java, Ruby, Perl, .Net, etc all succeed? I think, as a contributor to |
This is a JavaScript-specific vulnerability, and there is no reason for other languages to act in this case.
This is a JavaScript-specific vulnerability, and there is no reason for Elasticsearch to act in this case. Security is a concern that should be addressed at all levels. Once you are breached, there is no going back. Provide secure defaults is what guarantees to avoid security vulnerabilities and massive headaches afterward. The only thing that could be done here is to offer an option to make it even easier to disable this security check, such as |
You are quite right, this is a JavaScript vulnerability, and as such is the responsibility of the JavaScript developer to understand and mitigate. It is not the responsibility of the transport. Even if it were, a "fix" that breaks production systems is a very poor fix. Additionally, if it is so vital to the JS community, why is it not in Kibana? Incidentally, the PR in #1412 does not correctly describe (or rectify) the issue:
It is not just if the object contains those values, but if the data does. In that case, I would be grateful if the wider community could comment. |
Definitely! But this would also mean that you would see dozens of security breaches on the internet because security is hard and easy to get wrong.
I've understood your point, and as I've said, this library made some decisions, if you don't agree with them, you can easily override them, as the library is designed to allow you to do so.
This fix is in Kibana, the example you have shown won't trigger the error as it happens only if the I agree that the |
Is this safe? For example:
...why does the |
Hello! I didn’t express myself well, let me rectify my message: Thank you for your feedback, I’ll prepare a pull request that adds a |
I appreciate you looking at this complex security issue. I remain to be convinced that this is the correct place to attempt to enforce security and appreciate supported option to disable it, but I still don't see how it works in Kibana:
...produces:
Is this response considered safe? |
Can I ask why this has been closed? The issue still exists, and you have not explained why the above response is acceptable, given a code sequence such as #1414 does not, alone, fix the above security risk or bring the JS library into line with all the other client libraries. Additionally, it brings a false sense of security as it obviates the need for good security practices by the application developer by making some (top-level?) objects "safe", but not others. Why was there no review of this PR by other team members? |
Hello! The dev tools UI in Kibana is not using the client, but a plain HTTP proxy. |
🐛 Bug Report
Query fails with
DeserializationError: Object contains forbidden prototype property
.This started happening when we upgraded from v7.3 to v7.11. This PR seems to be the cause: #1110
To Reproduce
Issue a query that results in
constructor
being an object key in the JSON response. In our case it was detected in a request to the Term Vectors API, but I guess it can happen in many other places, like in an aggregation namedconstructor
, etc. Example from the Term Vectors API response that affected us:See #1110 (comment) for a full example.
Expected behavior
No errors thrown from a perfectly valid response.
Your Environment
@elastic/elasticsearch
version: 7.11The text was updated successfully, but these errors were encountered: