NoSQL Injection
NoSQL Injection
Description
NoSQL injection is a security vulnerability that occurs when attackers exploit weaknesses in applications using NoSQL databases. It involves injecting malicious or unexpected data into input fields, enabling attackers to manipulate queries and access unauthorized information.
Similar to SQL injection attacks against SQL databases, NoSQL injection targets applications utilizing NoSQL databases like MongoDB, Cassandra, or others. Attackers craft input, such as special characters or payloads, to manipulate NoSQL database queries executed by the application.
By injecting the crafted input, attackers aim to alter the logic of database queries, bypass authentication, or retrieve sensitive information stored in the database. NoSQL injection attacks can lead to unauthorized data access, data modification, or even the complete compromise of the database, compromising the confidentiality, integrity, and availability of the application and its data.
Examples
import com.mongodb.*;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/login")
public class NoSQLInjectionController {
@PostMapping
public void login(@RequestParam String userName, @RequestParam String password) {
MongoClientURI uri = new MongoClientURI("mongodb://localhost:27017");
MongoClient mongoClient = new MongoClient(uri);
try {
DB database = mongoClient.getDB("test");
DBCollection collection = database.getCollection("users");
BasicDBObject query = new BasicDBObject();
query.put("$where", "this.sharedWith == \"" + userName + "\" && this.password == \"" + password + "\"");
DBCursor cursor = collection.find(query);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
} finally {
mongoClient.close();
}
}
}
const MongoClient = require('mongodb').MongoClient;
const express = require('express');
const app = express();
app.post('/login', async (req, res) => {
const username = req.body.username;
const password = req.body.password;
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('test');
const usersCollection = database.collection('users');
// Vulnerable query susceptible to NoSQL Injection
query = { $where: `this.username == '${username}' && this.password == '${password}'` }
const user = await usersCollection.find(query);
res.json({ success: user !== null });
} finally {
await client.close();
}
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$manager = new MongoDB\Driver\Manager('mongodb://localhost:27017');
$query = [ "username" => $username, 'password' => $password ];
$testquery = new MongoDB\Driver\Query($query, []);
$cursor = $manager->executeQuery('test.users', $testquery);
foreach ($cursor as $document) {
var_dump($document);
}
?>
Recommendation
To prevent NoSQL injection attacks, consider the following measures:
-
Safe Query Construction: Construct queries using the database's specific methods or query builders provided by the API. Avoid directly concatenating user inputs into queries. Instead, use the appropriate mechanisms provided by the database API for safe query construction.
-
Input Validation and Sanitization: Implement robust input validation to ensure that user-supplied data meets expected formats. Use sanitization techniques like whitelisting acceptable characters to prevent unwanted input.
-
Use whitelist of accepted keys: To prevent operator injection, use a whitelist of accepted keys to prevent injection of query operators like
$where
,$in
,$ne
.
Examples
import com.mongodb.*;
import java.util.regex.Pattern;
public class SecureNoSQLInjection {
public static void main(String[] args) {
String username = sanitizeInput(args[0]);
String password = sanitizeInput(args[1]);
MongoClientURI uri = new MongoClientURI("mongodb://localhost:27017");
MongoClient mongoClient = new MongoClient(uri);
DB database = mongoClient.getDB("test");
DBCollection collection = database.getCollection("users");
BasicDBObject query = new BasicDBObject();
query.put("username", username);
query.put("password", password);
DBCursor cursor = collection.find(query);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
}
// Function to sanitize input (escape special characters)
private static String sanitizeInput(String input) {
return Pattern.quote(input); // Escapes special characters in the input string
}
}
const MongoClient = require('mongodb').MongoClient;
const express = require('express');
const mongoSanitize = require('mongo-sanitize');
const app = express();
// Middleware to parse incoming JSON requests
app.use(express.json());
app.post('/login', async (req, res) => {
const username = mongoSanitize.sanitize(req.body.username);
const password = mongoSanitize.sanitize(req.body.password);
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('test');
const usersCollection = database.collection('users');
// Secure query using parameterization to prevent NoSQL Injection
const user = await usersCollection.findOne({ username, password }); // Secure code with input sanitization
res.json({ success: user !== null });
} finally {
await client.close();
}
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
<?php
$username = $_POST['username'] ?? null;
$password = $_POST['password'] ?? null;
$sanitizedUsername = filter_var($username, FILTER_SANITIZE_STRING);
$manager = new MongoDB\Driver\Manager('mongodb://localhost:27017');
// Using prepared statements for the query
$query = new MongoDB\Driver\Query([
'username' => $sanitizedUsername,
'password' => ['$eq' => $password] // Use an exact match for the password
]);
try {
$cursor = $manager->executeQuery('test.users', $query);
foreach ($cursor as $document) {
var_dump($document);
}
} catch (MongoDB\Driver\Exception\Exception $e) {
echo "Exception: ", $e->getMessage();
}
?>
Links
Standards
- GDPR:
- ART_5
- ART_32
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_3
- REQ_6_5
- REQ_8_6
- SOC2_CONTROLS:
- CC_2_1
- CC_3_4
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5