I was reading my trusty O'Reilly book and came across a passage about how Mongo, by nature, avoids the morass of SQL injection-like flaws.
In my gut, I think I understand this. If unsanitized vars are passed into queries, they can't break out of the document-oriented query structure with a UNION
, JOIN
, query turned comment, etc.
How does MongoDB avoid the SQL injection mess? Is it just by nature of this query syntax?
MongoDB avoids the potential for problems by not parsing.
Any API, anywhere, that involves encoding user data in formatted text that gets parsed has the potential for the caller and callee to disagree on how that text should be parsed. These disagreements can be security issues when data is misinterpreted as metadata. This is true whether you're talking about printf format strings, including user generated content in HTML, or generating SQL.
Since MongoDB doesn't parse structured text to figure out what to do, there is no possibility of misinterpreting user input as instructions, and hence no possible security hole.
Incidentally the advice of avoiding APIs that require parsing is item 5 in http://cr.yp.to/qmail/guarantee.html. If you're interested in writing secure software, the other 6 suggestions are worth looking at as well.
Update (2018): The original answer as I gave it remains true to the best of my knowledge. From the point of what is sent to MongoDB to what is sent back, there is no SQL injection attack. The injection attacks that I'm aware of happen outside of MongoDB and are actually problems in how external languages and libraries set up the data structure that will be passed to MongoDB. Furthermore the location of the vulnerability is in how data is parsed on the way to becoming a data structure. Therefore the original answer accurately describes both how to avoid injection attacks, and what puts you at risk of them.
But this accuracy is cold comfort to a programmer who is hit by injection attacks from defects that were not obvious in their own code. Few of us distinguish between the external tool and all the layers between our code and that external tool. And the fact remains that it requires vigilance on our part to anticipate and close off injection attacks. With all tools. And this will remain the case for the foreseeable future.
To summarize the MongoDB documentation
BSON
As a client program assembles a query in MongoDB, it builds a
BSON object, not a string. Thus traditional SQL injection attacks are
not a problem.
However, MongoDB is not immune from injection attacks. As noted in the same documentation, injection attacks are still possible as MongoDB operations allow arbitrary JavaScript expressions to be executed directly on the server. The documentation goes into this in detail:
http://docs.mongodb.org/manual/faq/developers/#javascript
With PHP mongoDB can become vulnerable to No-SQL injection:
http://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-to-sql-injection-in-php-at-least/
http://www.php.net/manual/en/mongo.security.php
The database might not parse the content but there are other areas of the code that are vulnerable.
https://www.owasp.org/index.php/Testing_for_NoSQL_injection
To protect against SQL injection, clients can use MongoDB's language APIs. This way, all the input is simple value - commands cannot be injected. A Java example:
collection.find(Filters.eq("key", "input value"))
The drawback is that you cannot easily test your filter. You cannot copy it to Mongo's shell and test it. Especially problematic with bigger, more complex filters/queries.
BUT!!! there's also an API to not use the filter's API - enabling to parse any json filter. Java example below:
collection.find(BasicDBObject.parse("{key: "input value"}"));
This is nice because you can copy the filter directly to the MongoDB shell to test it out.
BUT!!! (last but, I promise) this is prone to NoSql injection. Java example, where the input value is {$gt: ""}
.
collection.find(BasicDBObject.parse("{key: {$gt: ""}}"));
In this last example, everything is returned, even though we meant only for the specific records to return.
See here a more thorough explanation on SQL injection when using the filters directly.
One last thing. I think there's a way to use both raw filters and still protect against SQL injection. For example, in Java, we can use Jongo's parameterized queries.