Nosql Injection with Api Keys
How NoSQL Injection Manifests in API Keys
NoSQL injection in API keys typically occurs when authentication or authorization logic constructs database queries using untrusted input from API keys without proper validation or sanitization. Unlike traditional SQL injection, NoSQL injection exploits the query syntax of document databases like MongoDB, DynamoDB, or Couchbase.
The most common attack pattern involves API keys being used as direct query parameters. For example, an API endpoint might accept an API key in the header and use it to look up user permissions:
const apiKey = req.headers['x-api-key'];
const user = await db.collection('users').findOne({ apiKey: apiKey });An attacker can manipulate the API key value to inject NoSQL operators. Since MongoDB and similar databases accept JSON-like query objects, submitting an API key like { "$ne": null } would return the first user document where apiKey is not null, effectively bypassing authentication.
Another manifestation occurs in role-based access control systems where API keys determine permissions. Consider this vulnerable pattern:
const { apiKey, resourceId } = req.query;
const query = { apiKey, resourceId };
const result = await db.collection('data').findOne(query);An attacker could submit resourceId[$ne]=null to retrieve any document matching their API key regardless of the intended resourceId filter, potentially exposing data from other users or resources.
Time-based NoSQL injection is also possible, where attackers use operators like $where with JavaScript functions to create conditional delays, helping them extract information through timing analysis. This is particularly dangerous in serverless environments where timing attacks can be amplified.
API Keys-Specific Detection
Detecting NoSQL injection in API keys requires both static analysis and dynamic testing. Static analysis involves reviewing code paths where API keys are used as database query parameters. Look for patterns where user input is directly interpolated into database queries without proper sanitization.
Dynamic testing with middleBrick scans specifically targets this vulnerability. The scanner tests API endpoints by submitting API keys containing NoSQL operators like $ne, $gt, $lt, $where, and $regex. For MongoDB-based APIs, middleBrick attempts authentication bypass by submitting keys that exploit query logic.
middleBrick's NoSQL injection detection includes:
- Authentication bypass attempts using
{ "$ne": null }patterns - Authorization bypass testing with
$existsand$regexoperators - Property access manipulation using dot notation injection
- JavaScript code injection via
$whereoperator testing
The scanner also analyzes API specifications to identify endpoints that accept API keys and correlate this with the backend database type. For OpenAPI specs, middleBrick resolves $ref paths to understand the complete authentication flow and identify potential injection points.
Runtime detection should include monitoring for unusual query patterns, such as API keys containing special characters or JSON structures that deviate from expected formats. Implementing request validation middleware that rejects API keys containing {, }, $, or other suspicious characters can prevent many injection attempts.
API Keys-Specific Remediation
Remediating NoSQL injection in API key systems requires a defense-in-depth approach. The primary fix is to never use API keys directly as database query parameters. Instead, use API keys as references to lookup records in a secure, indexed table.
// Vulnerable pattern - DO NOT USE
const apiKey = req.headers['x-api-key'];
const user = await db.collection('users').findOne({ apiKey: apiKey });// Secure pattern - USE THIS INSTEAD
const apiKey = req.headers['x-api-key'];
const apiRecord = await db.collection('api_keys').findOne({ key: apiKey });
if (!apiRecord) {
return res.status(401).json({ error: 'Invalid API key' });
}
const user = await db.collection('users').findOne({ _id: apiRecord.userId });This indirection prevents attackers from manipulating query operators since the API key is only used to lookup a single record in a dedicated collection.
Implement strict input validation for API keys. API keys should be treated as opaque strings with a fixed format (e.g., UUIDs, base64-encoded tokens, or hexadecimal strings). Validate the format before any database operations:
const apiKey = req.headers['x-api-key'];
if (!/^[a-f0-9-]{36}$/.test(apiKey)) {
return res.status(400).json({ error: 'Invalid API key format' });
}Use parameterized queries or query builders that automatically escape special characters. Most database drivers provide safe query construction methods:
// Using MongoDB's safe query builder
const { MongoClient } = require('mongodb');
const client = new MongoClient(uri);
const query = { apiKey: { $eq: apiKey } }; // Explicitly use $eq operator
const user = await client.db().collection('users').findOne(query);Implement API key rotation and revocation mechanisms. Store API keys as hashes (similar to password storage) rather than in plaintext. When validating, hash the provided key and compare against stored hashes:
const apiKey = req.headers['x-api-key'];
const apiRecord = await db.collection('api_keys').findOne({ keyHash: hash(apiKey) });Monitor API key usage patterns for anomalies. Set up alerts for API keys that access unusual resources or exhibit patterns consistent with injection attempts. middleBrick's continuous monitoring can help identify these patterns over time.