A NoSQL injection vulnerability is an error in a web application that uses a NoSQL database. This web application security issue lets a malicious party bypass authentication, extract data, modify data, or even gain complete control over the application. NoSQL injection attacks are the result of a lack of data sanitization.

NoSQL injections are just one of many injection attacks, similar to traditional SQL Injections. They are engineered to exploit modern databases that do not use SQL. The term NoSQL (not only SQL) is used to describe databases that use a less rigid structure and may refer to many different types of databases, including those that use models such as key-value, key-document, column-family, or graph.

While NoSQL database engines have a different structure and do not support SQL statements and SQL queries, they still let users perform queries. They do not support one standardized language and therefore the query language is dependent on the implementation: database (e.g. MongoDB, Redis, Google Cloud Datastore, etc.), language (e.g. Python, PHP, etc.), and framework (e.g. Node.js, Angular). However, NoSQL queries are most often based on JSON and they can include user input. If this input is not sanitized, they are vulnerable to injections.

MongoDB Injection Example in a PHP Application

To understand how a NoSQL query is constructed and how it is vulnerable to an injection attack, we will focus on the most popular NoSQL database: MongoDB, and we will access it using PHP. Here is a simple example of a code snippet that accesses a MongoDB for authentication purposes.

$username = $_POST['username'];
$password = $_POST['password'];
$connection = new MongoDB\Client('mongodb://localhost:27017');
if($connection) {
	$db = $connection->test;
	$users = $db->users;
	$query = array(
		"user" => $username,
		"password" => $password
	);
	$req = $users->findOne($query);
}

As you can see, in this example, username and password used for authentication are taken from a POST request and then directly used in the query. Similar to other types of injection, a malicious user may supply a NoSQL injection payload that tricks the database.

To perform a successful MongoDB injection, it is enough if the attacker supplies the following malicious input data as a POST request:

username[$eq]=admin&password[$ne]=foo

The [$ne] query operator means not equal. Therefore, the resulting query will find the first record in which the username is admin and the password is not foo. If this code is used for authentication, the attacker is logged in as the admin user.

More operators can be used in a similar fashion, for example [$lt] and [$gt] as well as [$regex]. Regular expressions can even allow the attacker to enumerate all users in the above scenario by trying combinations in sequence and evaluating the result.

Advanced Attacks and JavaScript Injections

MongoDB queries support a commonly used operator $where, which introduces possibilities of serious NoSQL attacks that include JavaScript objects.

For example, a developer might want to use the $where operator in the following fashion to access a record for a particular user:

$query = array('$where' => 'this.name === \''.$name.'\'');

In this situation, the attacker may provide the following empty string comparison trick as $name:

'; return '' == '

As a result, the query will become:

"$where": "this.name === ''; return '' == ''"

And the attacker will receive the entire list of users.

Since the $where operator is actually evaluated as JavaScript code, the attacker could also pass a malicious string that includes arbitrary JavaScript, for example:

'; while(true){}'

This example creates a neverending loop and causes a denial of service attack.

How to Avoid NoSQL Injections

To avoid NoSQL injections, you must always treat user input as untrusted. Here is what you can do to validate user input:

  • Use a sanitization library. For example, mongo-sanitize or mongoose.
  • If you can’t find a library for your environment, cast user input to the expected type. For example, cast usernames and passwords to strings.
  • In the case of MongoDB, never use where, mapReduce, or group operators with user input because these operators allow the attacker to inject JavaScript and are therefore much more dangerous than others. For extra safety, set javascriptEnabled to false in mongod.conf, if possible.
  • Additionally, always use the least-privilege model: run your application with the lowest privileges possible so that even if it gets exploited, the attacker cannot access other resources.
SHARE THIS POST
THE AUTHOR
Tomasz Andrzej Nidecki
Principal Cybersecurity Writer
Tomasz Andrzej Nidecki (also known as tonid) is a Primary Cybersecurity Writer at Invicti, focusing on Acunetix. A journalist, translator, and technical writer with 25 years of IT experience, Tomasz has been the Managing Editor of the hakin9 IT Security magazine in its early years and used to run a major technical blog dedicated to email security.