MongoDB will not prevent NoSQL injections in your Node.js app

NoSQL injections in Node.js with MongoDB

Last updated: December, 2020

The follow-up on how to prevent NoSQL injections in MongoDB in a Node.js app can be found here.

TL;DR – Mongo and Node.js are not safe by default

Using a NoSQL database does not make injections impossible. This article shows how a Node.js application based on Express and using MongoDB (with Mongoose ORM) can be vulnerable to NoSQL injections.

Good ol’ SQL injections

SQL injection is a pretty well-known attack. A SQL injection happens when a client sends SQL queries to a server and when those queries are executed.

Usually, a SQL injection is possible because of an unsafe string concatenation when creating a SQL query.

For instance, the following Express route pictures a vulnerable piece of code:

The developer expects the request parameter ‘id’ to be a string representing the id of an item in the database. The HTTP requests are expected to look like: GET /posts/150.

However, it is possible to inject arbitrary SQL code here, for instance, in order to get all items in the database, an attacker could perform the request GET ‘/posts/0 OR TRUE’.

In this situation, the attacker can do pretty much everything they want with the database. There is a large amount of SQL injection literature if that’s something you are interested in.

MongoDB (and other NoSQL databases) does not use SQL language for queries

We will focus on MongoDB (since it continues to be one of the most popular database within the Node.js community), however, the concepts described here apply to other NoSQL databases engines.

With the Node.js official MongoDB driver, requests are performed using a query API with query objects. For instance, querying all items in a collection whose ‘quantity’ field is greater than or equal to 0 would be done using:

We used the find method on the Items collection. The query object states that we want to filter on the quantity field and we used a MongoDB command $gte which means ‘greater than or equal’ to state our request.

If we wanted only the items whose quantity is 0, we could do:

Other methods that find exist and are referenced in the driver’s API.

NoSQL means not-injectable, right?

We first need to define what an injection would be here:

A MongoDB injection happens when a client is able to inject MongoDB commands that will be executed by the database engine.

In other words, the attacker will try to inject a custom object with MongoDB commands inside the query object. This would allow them to access more documents than they should be able to.

To provide an understandable example, we will use a very simple and naive project. You can find the whole code on Github. This projects has an endpoint to perform smart queries inside the Document collection:

The developer expects the payload of this request to contain a member named ‘title’ or a member named ‘type’. They also do not want the client to be able to query documents whose type is ‘secret projects’.

If we perform a few queries on this endpoint, we get the expected result:

Payload Result
{“type”:”secret projects”} Empty array
{ “type”: “blog” } All documents which type is ‘blog’
{ } Empty array

Time to perform an injection

There is no filtering on the nature of the query object here. The developer expects the value of ‘type’ in the payload to be a string.

However, nothing prevents an attacker from placing an object there. The attacker can also use MongoDB commands!

Payload Result
{ “type”: { “$gte”: “” } } All documents in the collection including the ‘secret projects’

The $gte command is compatible with strings.

One could claim that there is not much harm here. The attacker was not able to modify the content of the database. This would not be a good way of thinking:

  • This example shows how easy it is to perform massive data exfiltration from a vulnerable server. (Big players like Yahoo! know a bit about it)
  • Other methods that can change the content of the database exist and could be injectable. For instance:

updateMany(filter, update, options, callback)

Where:

  • `filter` is a query object that could be injectable
  • `update` is an object holding the rules regarding the modification of the documents for for which the predicate of `query` are true.

Other gotchas

  • The package used by Express to parse querystring is qs. This package parses querystrings as object. Querystrings are injectable.
  • Some MongoDB commands execute JavaScript code within the database engine. Those are `$where`, group, and map-reduce operations (see documentation here). Until MongoDB 2.4, the JavaScript code had access to the `db` object from within the query. That means that someone injecting such a command in your application could be able to do anything with the content of your database.

How do you protect yourself without pain?

Maintaining a data validation layer on every endpoint of an application can be very painful and time-consuming.

At Sqreen, we believe developers should be able to focus on developing their applications without having to constantly fear for security. We also believe in making security easy and transparent for developers and security teams alike.

Sqreen will block attacks in your application (including NoSQL injections, SQL injections, and XSS) without you having to take any action or change your code. The best thing is that Sqreen takes literally 30 seconds to install in a Node.js application.

Conclusion

In this short article, we saw how NoSQL injections are possible. The attack method is not really complicated and there are several ways to protect an application against such injections.

To learn a method to prevent MongoDB injections in a Node.js application, check out part two of this topic

Appendix

Here are the slides of the lightning talk I gave on this topic at the DotJS conference in 2016.

About the author

Vladimir de Turckheim is the Node.js lead engineer at Sqreen and was previously an expert in cybersecurity. He is involved in various open-source projects in JavaScript, mostly within the hapijs project.

Subscribe
Notify of
guest
8 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments