HIGH nosql injectiondjangomutual tls

Nosql Injection in Django with Mutual Tls

Nosql Injection in Django with Mutual Tls

Nosql Injection in Django occurs when untrusted input is used to construct query operations for a NoSQL database without proper validation or parameterization. In a typical Django setup, this might happen when developers use dict lookups or Q objects built from request data and then pass them to a NoSQL layer (for example, MongoDB via djongo or a custom backend). If the application also enforces Mutual Transport Layer Security (Mutual TLS), the presence of mTLS does not prevent injection—it only ensures that the client and server authenticate each other during TLS handshake. Therefore, an attacker who presents a valid client certificate can still send maliciously crafted query structures that the Django backend interprets as part of a NoSQL command.

Mutual TLS changes the threat surface in two ways. First, it narrows the set of clients that can reach the endpoint, which may create a false sense of security. Second, because the TLS layer terminates authentication before requests reach Django, developers might assume the incoming data is trustworthy. This assumption is dangerous: the mTLS client certificate proves identity, not intent. A compromised or malicious authenticated client can still supply data such as {"username": {"$ne": ""}} that, when used in a filter() or aggregate() call, leads to unauthorized data retrieval or modification. Common NoSQL injection patterns in Django include using unsanitized dictionary keys as field names, concatenating JSON strings into query expressions, and failing to validate array indices or operator usage ($where, $regex, $in).

Consider a Django view that accepts a JSON payload to filter user records via a NoSQL backend:

import json
from django.http import JsonResponse
def search_users(request):
    if request.method == "POST":
        filters = json.loads(request.body)
        # Danger: directly using user input in a NoSQL query
        results = UserCollection.find(filters)
        return JsonResponse(list(results), safe=False)
    return JsonResponse({"error": "POST required"}, status=405)

If an authenticated mTLS client sends {"$where": "this.password == " + " ".join(["1"]*10000)}, the backend may execute a heavy server-side operation or leak data. Similarly, using __raw__ or map_reduce with unchecked input can lead to privilege escalation or data exposure. Because the scan window is 5–15 seconds, such abuse can be attempted quickly, and findings will appear in the middleBrick report under Data Exposure and Unsafe Consumption checks.

Mutual Tls-Specific Remediation in Django

Remediation focuses on treating authenticated input as hostile even when mTLS is in place. You should validate and sanitize all data used to construct NoSQL queries, use parameterized APIs where available, and apply the principle of least privilege to the database account used by Django.

Below are concrete code examples for secure Django configurations with Mutual TLS. These examples assume you have certificates issued by a private CA and that your web server (e.g., Nginx) is configured to request and verify client certificates. Django itself does not handle TLS, so the examples show how to safely consume verified identity information and sanitize inputs.

1. Django settings to surface mTLS client certificate details (for auditing/logging only, not for query construction):

# settings.py
import os

SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# If your server sets the client certificate fields in headers:
CLIENT_CERT_HEADER = "SSL_CLIENT_CERT"  # Example header from the proxy
CLIENT_CERT_SUBJECT_HEADER = "SSL_CLIENT_S_DN"

2. A view that validates input and avoids direct NoSQL operator injection:

import json
from django.http import JsonResponse, HttpResponseBadRequest
from django.db import connection
def search_users_safe(request):
    if request.method != "POST":
        return JsonResponse({"error": "POST required"}, status=405)

    try:
        payload = json.loads(request.body)
    except json.JSONDecodeError:
        return HttpResponseBadRequest("Invalid JSON")

    # Strict allowlist of filterable fields
    allowed_fields = {"username", "email", "status"}
    safe_filters = {}

    for key, value in payload.items():
        if key not in allowed_fields:
            continue  # drop disallowed fields
        if key == "username" and not isinstance(value, str):
            continue
        if key == "email" and not isinstance(value, str):
            continue
        if key == "status" and value not in ("active", "inactive"):
            continue
        safe_filters[key] = value

    # Use a safe ORM path when possible; if using NoSQL driver, parameterize operators.
    # Example using a hypothetical NoSQL wrapper that supports parametrized queries:
    # results = UserCollection.find(safe_filters)
    # For demonstration with raw SQL-like parameterization concept:
    query = "SELECT * FROM users WHERE " + " AND ".join([f"{k}=%s" for k in safe_filters.keys()])
    with connection.cursor() as cursor:
        cursor.execute(query, list(safe_filters.values()))
        results = cursor.fetchall()

    return JsonResponse(list(results), safe=False)

3. Explicitly reject operators that can lead to injection:

import re
DANGEROUS_OPS = re.compile(r"^\\$[a-z]+", re.I)
def is_safe_filter(value):
    if isinstance(value, dict):
        return not any(DANGEROUS_OPS.match(k) for k in value.keys())
    return True

Use is_safe_filter to validate each filter clause before passing it to the NoSQL driver. This approach complements mTLS by ensuring that even authenticated requests cannot abuse operator-based injection.

Finally, integrate middleBrick to continuously scan your endpoints. Use the CLI to run scans from your terminal:

middlebrick scan <your-api-url>

For CI/CD, add the GitHub Action to fail builds if the security score drops below your chosen threshold, and consider the Pro plan for continuous monitoring and Slack/Teams alerts.

Frequently Asked Questions

Does Mutual TLS stop NoSQL injection in Django?
No. Mutual TLS authenticates the client and server but does not validate or sanitize input. Injection vulnerabilities depend on how the application uses request data in queries.
How can I detect NoSQL injection in my Django API?
Run scans with tools that test query manipulation and operator usage. middleBrick performs black-box checks for Injection and Unsafe Consumption and provides prioritized findings with remediation guidance.