75 lines
2.6 KiB
Plaintext
75 lines
2.6 KiB
Plaintext
== How to fix it in MongoDB
|
|
|
|
=== Code examples
|
|
|
|
The following code is vulnerable to arbitrary code execution because it builds
|
|
a JavaScript code snippet from untrusted data. This piece of code is then used
|
|
as an operand for a dangerous *evaluation* MongoDB operator.
|
|
|
|
When performing a database query that way, the MongoDB server will interpret
|
|
the JavaScript code as part of the data retrieval process. This might lead to
|
|
arbitrary code execution on the database server.
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,javascript,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
const client = new MongoClient(mongoURI);
|
|
async function run() {
|
|
const database = client.db('example');
|
|
const products = database.collection('product');
|
|
const query = { $where: `isString(this.${req.query.prop})`};
|
|
const product = await products.findOne(query); // Noncompliant
|
|
}
|
|
run().catch(console.dir);
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,javascript,diff-id=1,diff-type=compliant]
|
|
----
|
|
const client = new MongoClient(mongoURI);
|
|
async function run() {
|
|
const allowed = ["name", "price", "stock"]
|
|
|
|
let propId = req.query.propId
|
|
const database = client.db('example');
|
|
const products = database.collection('product');
|
|
const query = { $where: `isString(this.${allowed[propId]})`};
|
|
const product = await products.findOne(query); // Noncompliant
|
|
}
|
|
run().catch(console.dir);
|
|
----
|
|
|
|
=== How does this work?
|
|
|
|
MongoDB provides JavaScript code-aware search operators to allow developers to
|
|
perform advanced queries. In most cases, the same result can be achieved by
|
|
combining classical, safer, operators, or by performing additional data
|
|
filtering on the application side.
|
|
|
|
Note that MongoDB servers implement a sandboxed JavaScript engine to run the
|
|
operator-related code. Without other vulnerabilities in the database engine,
|
|
the execution of arbitrary code is thus not possible through the exploitation
|
|
of evaluation operators. However, a successful injection could still lead to
|
|
the compromise of the MongoDB server hosted data. Moreover, the discovery by
|
|
an attacker of a way to escape the sandbox should also be considered.
|
|
|
|
==== Safer operators
|
|
|
|
Wherever possible, safe operators that do not evaluate JavaScript
|
|
expressions should be preferred over dangerous ones. Dangerous operators
|
|
include:
|
|
* `$where`
|
|
* `$accumulator`
|
|
* `$function`
|
|
|
|
If the application requires a complex logic to properly filter a query's
|
|
results, it might be considered to implement it on the application side rather
|
|
than in the database itself. That way, only simple operators can be used in the
|
|
database query.
|
|
|
|
include::../../common/fix/allowlist.adoc[]
|
|
|
|
The example compliant code uses such a binding approach.
|