-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
Transform unsafe fields in Elasticsearch client payloads #109544
Comments
Pinging @elastic/kibana-security (Team:Security) |
We currently don't have any wrapper around the library's client, we're just using a vanilla client and only customizing it via the allowed configuration options. So before going any further, we need to make sure this proposal could be done by just client configuration.
A system request being a request against a Kibana system index then, right? Got some doubts about the technical feasability. I'm unsure we can override such options on a request basis ? I know we're using a custom
The I see the client does accept a export interface SerializerOptions {
disablePrototypePoisoningProtection: boolean | 'proto' | 'constructor'
}
export default class Serializer {
constructor (opts?: SerializerOptions)
serialize(object: any): string;
deserialize(json: string): any;
ndserialize(array: any[]): string;
qserialize(object: any): string;
} Just to be clear: if from a security standpoint, this feature is considered mandator, can't be done via the plain client, and requires us to rethink the viability of a wrapper or proxy around the vanilla client, I'm not opposed to re-open the discussion. However, this would come at a performance (and development) cost, so I really want to make sure this is a necessity. |
Currently you can't disable the protection on a per-request basis. As per discussion with @mshustov and @legrego, you can disable it client-wide, as we'll disable/remove that options in the version 8 of the client. |
To attack a Kibana instance, an abuser should have
Kibana provides two interfaces to interact with the Elasticsearch server:
So, it sounds like we can set
But if we allow users to supply data with |
A system request being the usage of the
I didn't mean to suggest that we attempt to change the config on a per-request basis. Though, if this is getting removed in version 8 of the client anyway, I guess we don't need to make a distinction.
Sorry, I meant the Core Edit: forgot to respond to this too
I believe we can do everything we need on a per-client basis using the
The concern here is that granting a user
Yeah, that's what I was trying to suggest!
Yeah, that would be the tradeoff here. They can still create visualizations or filters but they would need to use the "transformed" field name. If we implemented my suggestion above, that would be |
I'm not sure I'm 100% following the suggestion to transform dangerous field names but generally speaking I'm not so crazy about the idea as it seems like it would require extra handling when creating queries. I assume they'd need to be transformed back at some point. IMO it seems that we should be avoiding object mutation since thats the mechanism by which these problematic field names have unwanted behavior. Its as simple as using |
both |
@mattkime Yes that's true, we could blindly remove all instances of the prefix such as
Agreed, and I'd like to do that in the long term, it's just figuring out how we get there that's the hard part. As mentioned we don't have a viable way to audit for such object mutation.
@pgayvallet Can you point to an example of this? The |
Not necessarily. I'm sure that most of us indirectly have write access to clusters somewhere by virtue of agents that are installed on our machines. They ship information about a runtime that is under our control (our laptops), to a cluster that is not within our control.
The event log is a good example of a system (hidden?) index that is accessed by both the internal and current users. I tend to agree with @mattkime -- rewriting these fields for the sake of safety is probably going to cause more problems than it solves, and could lead to confusion ("why is my field named dangerousJsonField-proto? That's not what it's called in my index!")
I think this is the right answer, but it will probably take years to get to the point where this is possible -- and even then, it won't be possible to enforce this. Maybe it makes sense to expose |
I am worried about the "whack-a-mole" effect of this. We can fix things on a case-by-case basis but doing this may uncover additional scenarios where these fields break other app experiences. Then we've got multiple Kibana versions that handle this differently for different plugins, and support becomes a nightmare. If we can't stomach the transformation (seemed like a palatable idea at first but I think the concerns are quite valid), perhaps we should just go with the original plan, disable this across Kibana, and redouble our efforts to catch these prototype pollution vulnerabilities. |
Considering @mattkime wants to land a fix in
|
@legrego , @mshustov , @pgayvallet and I met today to discuss this proposal and other options. Here's where we landed:
So, the safest and most reasonable thing to do is to disable |
I get that protecting against prototype pollution is super hard. However, non-dot-prefixed indices contain documents that we should effectively be treating as unsafe user input. We need some solution here. It doesn't have to be this very instant, but we should not assume that if a user can write a document to Elasticsearch that they are a trusted user who should be able to execute arbitrary code on the server that runs Kibana.
Do you mind elaborating on this? Starting in 8.0, users will have to explicitly circumvent the protections that we've put in place to prevent users from reading/writing Kibana's system-indices. |
Agreed.
The two examples that were brought up to me were the event log and ML jobs. There are only two ES clients provided by Core, one for the internal user and one for the current user. There is overlap between the indices that both of these clients access. |
I can only speak definitively about the event log, but Kibana is the only thing that should be writing documents to the event log; however, end-users can read these documents directly if they need "free form analysis". While it's technically possible that an end-user could write documents to the event log indices if they were given privileges to do so, they would break functionality in Kibana that reads the documents from the event log using the system user. This is a nitpick and doesn't impact the situation, but the event log indices are technically "hidden indices" not "system indices". |
Makes sense. Sorry, I was trying to clarify but I didn't outright state: we don't have the ability to dynamically change the ES client config based on whether the consumer is accessing a system index or not. We only have the ability to change the ES client config based on whether the internal user is being used or not. So while the internal user is generally used for system indices, it is not always -- some of the indices it accesses are not system indices, like you mentioned about the event log. It follows then that if we attempted to simply leave this protection in place for the client that is used by the internal user, there can be cases where regular users can manipulate some of these "overlapping" indices and cause a DoS. |
We decided to move forward and merge #109425. As @legrego mentioned in #109425 (comment), we need to prioritize a cohesive plan for addressing prototype pollution, and we'll do so in #58040. |
The Elasticsearch Node.js client (ES client) has prototype pollution protection enabled by default; if an unsafe field is detected (
constructor.prototype
or__proto__
), it throws an error. This protection can be optionally disabled by using thedisablePrototypePoisoningProtection
option.Over the past 9 months we have slowly been moving all consumers to use this new ES client (#83910). This default protection has broken legitimate usage of ES documents with the
__proto__
field in at least one instance (#101944). We considered a few options on how to handle this:disablePrototypePoisoningProtection: true
by default for the client, it will fix this issue but also put Kibana widely at risk for prototype pollution attacks (and possible remote code execution as a result). The attack surface is quite large and hard/impossible to audit or quantify. The problem is that downstream consumers can potentially use the ES client payloads in an insecure manner.disablePrototypePoisoningProtection: true
on a case-by-case basis, this likely turns into a big game of whack-a-mole. In this instance, the index pattern would be able to load the fields correctly, but then any subsequent calls by other consumers to load the documents for that index would run into this problem.That leads me to proposing what seems like the least-bad approach:
disablePrototypePoisoningProtection: true
for non-system requests (e.g., to data indices)ElasticsearchClient
to transform these problematic fields; we can add a prefix such asdangerousJsonField-
to ES responses and remove it from ES requestsThis allows all downstream consumers to continue functioning while keeping broad prototype pollution protection in place. The risk is that it breaks any existing filters, searches, visualizations, etc. that used the raw
constructor.prototype
or__proto__
fields back in old Kibana versions when these were allowed. I think it's safe to assume that usage of this is pretty rare.This isn't an ideal solution but I don't see a better alternative without a massive refactoring effort (such as forcing consumers to use
Map
, which is a safe way to interact with these dangerous fields).Side notes:
ElasticsearchClient
currently only surfaces these error messages in the debug logs. If it encounters the "Object contains forbidden prototype property" error, it should surface these in error logs instead.constructor.prototype
or__proto__
fields in Kibana -- in other words, system indices should not need to use these fields [citation needed]. We can probably leave the existing prototype poisoning protection in place for system requests. Alternatively, we can also use the proposed transformation approach.constructor.prototype
and__proto__
fields are encountered so we can better gauge if any follow-on work is needed. We already have thecore-usage-stats
saved object where we can add a counter that is incremented whenever dangerous fields are encountered/transformed.The text was updated successfully, but these errors were encountered: