A list of resources about NoSQL injection in general and PHP and MongoDB security specifically.
- Intro: NoSQL Databases
- No Security by Default: NoSQL Authentication
- MongoDB Injection into JavaScript
- MongoDB Request Injection Attacks
- PHP & MongoDB: execute
- Securing NoSQL
- NoSQL Injection Example Code
- Links: More about NoSQL Security
Intro: NoSQL Databases
NoSQL databases such as MongoDB are used more and more, but there isn’t a lot of information about the security of specific NoSQL databases or the security of NoSQL in general. The direction it seems to be going is: It’s not SQL, so SQL injection is not possible, so it is secure. This is of course not true at all. The damage that can be achieved with NoSQL injections does seem to be smaller than that of SQL injection, but that does not mean that developers should not care about it.No Security by Default: NoSQL Authentication
In MongoDB, authentication is disabled by default, which means that anyone has unlimited access to the database. Authentication is disabled because it is assumed that MongoDB runs in a trusted environment. This is not a good assumption to make, systems should really be secure by default.
MongoDB is not the only NoSQL database that fails miserably to provide security by enabling authentication by default: For example, the same is true of Apache CouchDB.
MongoDB Injection into JavaScript
MongoDB allows JavaScript filter functions to be used. A simplistic example might look like this (example is in PHP, but obviously other platforms and languages can be vulnerable as well, such as NodeJS):
// vulnerable code:
$whereClause = "function() {
var searchName = '" . $_GET['n'] . "'; "
. "return this.name == searchName;"
. "}";
$cursor = $users->find(array('$where' => $whereClause));
An attacker would just have to break out of the string and can then execute their own JavaScript code: [localhost/mdb.php?n=’;[injected code]var foo=’bar](). The problem is the same as with SQL injection: user input is interpreted as part of the language and executed. In the case of SQL injection it is SQL code, in the case of NoSQL injection it is JavaScript that gets executed.
With this, the attacker has a lot of options to do damage: They can DOS the server by injecting while(1);
or bypass filters by injecting return(true);
. Until version 2.4 of MongoDB, the db object was a global object, which means that an attacker could actually add data to the database, or perform a blind injection attack to retrieve data from the database.
Additionally to the where clause, injections are possible into eval, mapReduce, and group.
MongoDB Request Injection Attacks
It is possible to inject NoSQL keywords into queries that do not contain JavaScript themselves, and thus to bypass filters (for example listing more users than acceptable or bypassing a login). This could for example look like this:
// vulnerable code:
$cursor = $users->find(array('name' => $_GET['n'], 'password' => $_GET['p']));
An attack would look like this: [localhost/mdb.php?n=test&p[$ne]=1]() which results in a find call that would look like this:
$cursor = $users->find(array('name' => $_GET['n'], 'password' => array("$ne" => 1)));
So it looks for a user named test, with a password that is not 1 (which will be true for most users).
You can read more about this filter injection attack here. It is not only a problem with PHP and MongoDB, but also with NodeJS and MongoDB, and possibly other languages as well (all languages that allow an array with defined indices to be passed as GET or POST).
PHP & MongoDB: execute
This is actually a thing PHP warns about, although it should be obvious not to pass unfiltered user input to a function called execute:
// obviously vulnerable code:
$db->execute("print('Hello, $username!');");
Securing NoSQL
Right now, there are no pre-existing frameworks for securing MongoDB from injection attacks. But you might want to:
- turn on authentication (in MongoDB this is done via –auth)
- disable server side JavaScript completely via –noscripting (reduces functionality as it makes where, eval, mapReduce and group unusable)
- escape relevant characters (‘, “, $)
NoSQL Injection Example Code
Here is an example script for the described NoSQL injections in PHP and MongoDB in case you want to play with it yourself: PHP + MongoDB NoSQL injection Code Example
Links: More about NoSQL Security
- MongoDB CSRF, NoSQL injection, SSJI [pdf]
- Security options and settings in MongoDB, Cassandra, Neo4J
- PHP and MongoDB: Security Guide (not very in-depth)
- PHP and MongoDB: Injection
- MongoDB: Blind Injection [pdf]
- MongoDB and JSP: Injection (an injection not covered above because I could not reproduce it)