NoSQL Injection

ID

javascript.nosql_injection

Severity

critical

Resource

Injection

Language

JavaScript

Tags

CWE:943, NIST.SP.800-53, OWASP:2021:A3, PCI-DSS:6.5.1

Description

Improper Neutralization of Special Elements in Data Query Logic ("NoSQL Injection")

NoSQL Injection exploits weaknesses in applications interacting with NoSQL databases, such as MongoDB or Couchbase, by manipulating input data to alter query execution.

Unlike traditional SQL injections, which rely on SQL syntax, NoSQL injections leverage the flexible, schema-less nature of NoSQL databases.

Rationale

NoSQL databases often provide "query-by-example" capabilities, allowing users to construct queries from JSON without the need for SQL-like syntax. Unfortunately, this flexibility comes with the potential for NoSQL Injection vulnerabilities.

For example, a MongoDB query such as

db.users.find({ username: username, password: password })

could be altered using query and projection operators: username={"gt": ""} and `password={"gt": ""} match to mach any document.

The following is an example of a NoSQL Injection vulnerability in JavaScript code:

const express = require("express")
const app = express()
const dbUrl = "mongodb://..." // remember, do not leak credentials!
const MongoClient = require("mongodb").MongoClient;
// ...

app.post('/user', function (req, res) {
  MongoClient.connect(dbUrl, function (err, db) {

    // FLAW, vulnerble to NoSQL Injection using query operators
    let query = {
      username: req.body.username,
      password: req.body.password
    }

    db.collection('users')
      .findOne(query, function (err, user) {
        // ...
      });
  })
})

Remediation

To fix the above NoSQL Injection vulnerability, you need to sanitize the input to prevent it from being used as a query. Here we use the mongo-sanitize package:

const sanitize = require('mongo-sanitize')

app.post('/user', function (req, res) {
  MongoClient.connect(dbUrl, function (err, db) {
    // FIXED
    let query = {
      username: sanitize(req.body.username),
      password: sanitize(req.body.password)
    }

    db.collection('users')
      .findOne(query, (err, user) => {
      // ...
    })
  })
})

To mitigate NoSQL Injection risks in applications, follow these best practices:

  1. Input Validation: Rigorously validate inputs before processing them in NoSQL queries. Apply strict checks on data types, lengths, and formats.

  2. Use of Binding Mechanisms: Prefer using binding mechanisms or parameterized query structures provided by the NoSQL database’s library when assembling queries. This approach helps separate data from query logic.

  3. Sanitization: When using user inputs in query objects, ensure they are sanitized and free from characters or patterns that could be interpreted as part of a query structure. This is hard to do and error-prone, so consider first using binding mechanisms for parameterized queries, when available.

  4. Whitelist Validation: Implement whitelisting for input validation to ensure only expected values are allowed and unexpected input is rejected.

  5. Access Controls and Principle of Least Privilege: Implement strict access controls at the database level, and ensure that applications access only permitted data. Use credentials with the least privileges needed for the functionality.

  6. Regular Security Audits and SAST: Regularly audit your codebase for security vulnerabilities and include SAST tools in your development pipeline to catch potential NoSQL injections early in the development process.

By adopting these measures, you reduce the risk of NoSQL Injection vulnerabilities in your applications, protecting your database’s integrity and confidentiality.

Configuration

The detector has the following configurable parameters:

  • sources, that indicates the source kinds to check.

  • neutralizations, that indicates the neutralization kinds to check.

Unless you need to change the default behavior, you typically do not need to configure this detector.

References