1

I have a DB that I would like to expose to end users for flexible search through their data. Currently using Elastic, but not tied to that: I can internally transform the data in any way to enable secure, flexible querying.

What I'm curious about is how to expose a query language such as Elastic's Simple query string DSL in a safe way. I see hints like in this thread that simple query is safe to expose to end users, but nothing of the sort on the documentation page.

My application would authenticate users the usual way, add filters to their query based on user ID, and then forward the query directly to Elastic.

Here are some of my safety concerns:

  • Injection attacks enabling writes
  • Injection attacks to bypass user ID query filtering logic
  • DDoS

Any advice in this area is appreciated - I imagine there are well-used approaches because this seems like a fairly common problem, but I couldn't find anything clear.

2
  • Welcome to the community. You will need to at least one layer in between which filters out the bad stuff, ideally also use a WAF. Commented Apr 26 at 15:59
  • A little tangent, but this question have some pointers on why it's a bad idea.
    – ThoriumBR
    Commented Apr 26 at 17:37

1 Answer 1

2

Your approach doesn't require a library except a JSON serializer and an HTTP client. This is all very straightforward. I also doubt that it's common to expose the Elasticsearch API to the client. The common approaches for data APIs are REST and GraphQL, not a direct interface to the underlying database.

As to security: Allowing users to specify the simple_query_string attribute is reasonably secure under the following conditions.

  • Restrict the Elasticsearch user account you're going to use for the queries. Disallow everything that isn't strictly necessary. For example, if the end users shouldn't be able to change data, then don't give the account this privilege at all. This provides basic security even in the worst case where a user has managed to manipulate the HTTP request sent to the Elasticsearch API.
  • When you build the JSON document for the Elasticsearch API, you must first write all attributes (the query, filters etc.) to a data structure of the application language (e.g., a hash map or an object). Then serialize this data structure with a properly written and maintained JSON library. This will prevent injection attacks, because the attacker cannot “break out” of the simple_query_string attribute to overwrite, for example, the filter attribute. The application language and the JSON library ensure that individual JSON values (which may be user-controlled) cannot change the structure of the JSON document. In contrast, if you build the JSON document as a string by concatenating hard-coded and user-controlled fragments, there's a very high risk of an injection vulnerability, because an attacker may very well be able to overwrite parts of the document.
  • As an additional security measure, you could deserialize the serialized object again (possibly with a different JSON library) and check that it matches the original data structure. This would catch successful attacks against the serialization procedure -- however unlikely they may be.
  • Set timeouts and possibly other resource limits (either through Elasticsearch or in the operating system) to make DOS attacks more difficult.

In any case, there are probably better ways for providing data to users, both in terms of security and usability. The simple query syntax is rather obscure. Unless you're specifically dealing with experts who are willing to learn it just for your application, your users will probably struggle or only use a fraction of the possible features. Ask yourself if custom queries are really necessary. In many cases, people only need rather simple searches to get the data they want. A REST or GraphQL API might be perfectly sufficient. Of course the underlying application may very well use Elasticsearch internally.

3
  • Based on your answer, I think simple_query_string is a reasonable solution. For some context, the API is supposed to be similar to Datadog's log search syntax, or comparable in expressiveness to Github's search syntax. To clarify about the security conditions of simple_query_string, I think you're saying I have to protect against attacks against this structure, using a JSON library to serialize this kind of object. (Is this what you mean?) Object: { "query": { "simple_query_string": { "fields": [ "content" ], "query": "foo bar -baz" } } } Commented Apr 29 at 13:53
  • You have to prevent any vulnerability where the attacker is able to terminate the query string and manipulate the following JSON attributes or inject new ones. If you build the JSON object from individual strings, this can easily happen. For example, a single double quote which isn't properly escaped with a backslash lets an attacker "break out" of the string. But if you first create a data structure in the application language (let's say a Java hash map or an associate array in PHP) and then serialize this data structure with a JSON library, all attributes should be properly separated.
    – Ja1024
    Commented Apr 29 at 15:09
  • As long as you take the above measures into account, I see no major security problems. By the way, the documention does say that simple_query_string is suitable for end users. (on the bottom of the page). Of course such statements shouldn't be trusted blindly, but it confirms that exposing this particular attribute to end users is valid according to the API design.
    – Ja1024
    Commented Apr 29 at 15:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .