NoSQL Injection

Below you'll find a sample chapter from Secure Meteor; a guide to help you learn the ins and outs of securing your Meteor application from a Meteor security professional. If you like what you read and you're interested in securing your Meteor application, be sure to read the entire book!

Let’s consider another, more insidious example of what can happen to an application that doesn’t thoroughly check its Meteor method and publication arguments.

Within our Meteor-powered online storefront, we’ve built a shopping cart system to let our users track and save the items they’re interested in purchasing. Like any other shopping cart system, we give our users the ability to empty their cart.

When a user clicks the “empty cart” button, their client makes a call to the emptyCart Meteor method, passing up the shopping cart’s MongoDB identifier. The emptyCart method simply removes the items (or “line items”) in that cart from the database, effectively leaving the cart empty:

It’s important to realize that while our Meteor method assumes that cartId is a string, it’s never explicitly stating that assumption or making any assertion about cartId’s type.

A potentially malicious user could easily violate this assumption by manually calling the emptyCart method from their browser’s console and passing in a dangerous value for cartId:

In this example, the malicious user has called the emptyCart method and specified a cartId of { $gte: "" }. Placing this value of cartId into our LineItems.remove query results in the following query expression:

Rather than deleting a single user’s items from their shopping cart, this query removes every item from every shopping cart in the database, whether they belong to the user calling the method or not.

The object the malicious user passed into the emptyCart method is a MongoDB query operator. Specifically, a “greater than or equal to an empty string” query operator. When dropped into the rest of our LineItems.remove query, we’re essentially telling the database to remove all line items in the database who’s _id is “greater than or equal to an empty string.” Every line item’s _id will be greater than an empty string, so every line item will be removed.

Devastating.

This type of attack is known as a “NoSQL Injection” attack. NoSQL Injection vulnerabilities are incredibly dangerous and are particularly prevalent and relevant in Meteor applications, due to Meteor’s tight coupling to MongoDB and its seamless communication of disparate types through its DDP protocol.

NoSQL Injection vulnerabilities are incredibly dangerous and are particularly prevalent and relevant in Meteor applications.

Ultimately, NoSQL Injection attacks make their way into your application through missing, incomplete, or incorrect checking or user-provided data.

In this example, we could have easily prevented this devastating NoSQL Injection attack by explicitly voicing the assumption we’re making about the cartId argument of the emptyCart method. Let’s add a check that asserts that cartId is, in fact, the string we’re assuming it to be:

By making an assertion about the type of cartId, we’ve completely prevented the possibility of a NoSQL Injection attack. If our malicious user tries to pass in their MongoDB query operator, they’ll receive a type error in response.

Remember, it’s incredibly important to always check your arguments. Trusting user-provided data can the open door to worlds of hurt for your application, your organization, and your users.