Nosql Injection with Hmac Signatures
How Nosql Injection Manifests in Hmac Signatures
Nosql Injection in Hmac Signatures contexts typically occurs when cryptographic signatures are used to authenticate database queries without proper input sanitization. Attackers can manipulate signature parameters to inject NoSQL operators like $where, $ne, or $regex into query conditions.
Consider a Node.js API that verifies HMAC signatures before executing database operations:
const crypto = require('crypto');
const db = require('./db');
async function verifyAndQuery(req) {
const { userId, signature } = req.body;
// Verify HMAC signature
const computedSig = crypto.createHmac('sha256', process.env.SECRET_KEY)
.update(userId)
.digest('hex');
if (computedSig !== signature) {
return { error: 'Invalid signature' };
}
// Execute query based on signed userId
return await db.collection('users').findOne({ _id: userId });
}The vulnerability appears when userId contains NoSQL operators. An attacker can craft a payload like:
{
"userId": "{ \"$where\": \"this.isAdmin === true\" }",
"signature": "valid-hmac-here"
}Since the HMAC verification passes (the signature is valid for the string value), the NoSQL query executes with the injected operator, potentially returning admin users or bypassing authorization.
Another attack vector involves exploiting type coercion in NoSQL databases. MongoDB, for example, treats strings and ObjectId differently:
// Malicious payload
{
"userId": "{ \"$ne\": \"valid-user-id\" }",
"signature": "hmac-of-string"
}This returns all users except the specified one, leaking data through information disclosure.
Hmac Signatures-Specific Detection
Detecting NoSQL Injection in HMAC-signed requests requires examining both the cryptographic validation logic and the database query construction. middleBrick's scanner specifically tests for this by:
- Crafting HMAC signatures for payloads containing NoSQL operators
- Observing database responses to determine if operators are being executed
- Checking for timing differences that might indicate conditional query execution
The scanner tests 12 common NoSQL injection patterns in HMAC contexts:
middlebrick scan https://api.example.com/verify-signature \
--payload-type nosql-hmac \
--test-patterns $where,$ne,$gt,$regex,$size,$exists,$all,$elemMatch,$not,$nor,$and,$orKey detection indicators include:
| Indicator | Description | Risk Level |
|---|---|---|
| Operator execution | Database returns results matching injected NoSQL operators | Critical |
| Timing analysis | Response times vary based on conditional logic in NoSQL queries | High |
| Type coercion | Different results when string vs ObjectId values are used | Medium |
| Schema leakage | API reveals database structure through error messages | Medium |
middleBrick also analyzes OpenAPI specifications to identify endpoints using HMAC signatures and flags those that accept complex objects rather than simple primitives, which are more susceptible to NoSQL injection.
Hmac Signatures-Specific Remediation
Securing HMAC-signed endpoints against NoSQL injection requires defense in depth. The primary strategies are strict input validation, type enforcement, and query parameterization.
First, enforce strict type validation before signature verification:
async function verifyAndQuery(req) {
const { userId } = req.body;
// Validate userId is a simple string without special characters
if (typeof userId !== 'string' || /[^a-zA-Z0-9-]/.test(userId)) {
return { error: 'Invalid userId format' };
}
// Verify HMAC signature
const computedSig = crypto.createHmac('sha256', process.env.SECRET_KEY)
.update(userId)
.digest('hex');
if (computedSig !== req.body.signature) {
return { error: 'Invalid signature' };
}
// Use parameterized queries with strict typing
const query = { _id: new ObjectId(userId) };
return await db.collection('users').findOne(query);
}Key improvements:
- Input validation rejects objects and special characters before HMAC verification
- Type coercion is prevented by explicitly converting to ObjectId
- Query parameters are constructed separately from user input
For APIs that must accept complex objects, use a two-step validation approach:
function validateAndNormalizePayload(payload) {
// Create a whitelist of allowed fields
const allowedFields = ['userId', 'timestamp', 'action'];
// Ensure payload is a flat object with only allowed fields
const normalized = {};
for (const field of allowedFields) {
if (field in payload) {
const value = payload[field];
// Reject objects, arrays, and special characters
if (typeof value === 'object' || /[^a-zA-Z0-9-_.]/.test(String(value))) {
throw new Error('Invalid field value');
}
normalized[field] = String(value);
}
}
return normalized;
}Additional protections include:
- Using database query builders that automatically escape NoSQL operators
- Implementing rate limiting to slow brute-force attempts
- Adding audit logging for all HMAC-verified operations
- Using constant-time comparison for signature verification to prevent timing attacks
Frequently Asked Questions
Why doesn't HMAC signature verification prevent NoSQL injection?
Can NoSQL injection in HMAC contexts lead to authentication bypass?
$where or $ne to manipulate query results. This can return unauthorized data or even bypass authentication checks by exploiting conditional logic in the database queries.