NoSQL-Datenbanken haben eigene Injection-Klassen, die anders aussehen als SQL-Injection. Statt String-Konkatenation in SQL-Statements ist die häufigste Schwachstelle die direkte Übergabe von JSON-Objekten mit User-kontrollierten Operator-Feldern ($where, $ne, $gt, $regex). MongoDB ist der häufigste Fall — die Konzepte gelten aber analog für CouchDB, Elasticsearch und andere dokument-orientierte Datenbanken.

Wie NoSQL-Injection funktioniert

MongoDB-Queries sind JSON-Objekte:

JavaScript mongodb-basic-query.js
// Standard-Query
db.users.findOne({ username: 'alice', password: 'secret' });

Wenn eine Anwendung User-Input als Objekt entgegennimmt und ungesäubert in die Query gibt, kann ein:e Angreifer:in Operator-Felder einschleusen.

Beispiel-Schwachstelle:

JavaScript mongo-injection-login.js
// Schadhaft
app.post('/login', async (req, res) => {
  const user = await db.users.findOne({
    username: req.body.username,
    password: req.body.password,
  });
  if (user) {
    // Login erfolgreich
  }
});

Wenn req.body ein Objekt mit Operator-Werten enthält, wird der Login zur Lotterie:

JSON login-bypass-payload.json
{
  "username": "admin",
  "password": { "$ne": "x" }
}

MongoDB interpretiert: „Username = admin UND Password ungleich 'x'". Da das Passwort kein 'x' ist, matcht jedes User-Konto. Login-Bypass mit drei Zeichen JSON.

Voraussetzung: Body-Parser akzeptiert verschachtelte Objekte (Express body-parser Default, Koa, FastAPI mit JSON-Schema, etc.).

Die gefährlichsten MongoDB-Operatoren

$ne — Not Equal:

Wie oben gezeigt — { field: { $ne: 'x' } } matcht alles außer dem Wert 'x'. Klassischer Auth-Bypass.

$gt, $gte, $lt, $lte — Größer/Kleiner:

JSON gt-payload.json
{ "username": "admin", "password": { "$gt": "" } }

$gt: "" ist immer wahr für nicht-leere Strings — Login-Bypass.

$regex — Regex-Matching:

JSON regex-payload.json
{ "username": "admin", "password": { "$regex": "^a" } }

Mit Regex-Tricks kann ein:e Angreifer:in zeichenweise das Passwort extrahieren (Boolean-Blind-Variante).

$where — JavaScript-Eval:

Der gefährlichste Operator. $where lässt JavaScript im DB-Server laufen:

JSON where-payload.json
{ "$where": "this.password.match(/^a/) || sleep(5000)" }

Mit $where ist im Prinzip Server-Side Code-Execution möglich (im Sandbox-Modus der MongoDB-Engine). MongoDB hat in neueren Versionen $where standardmäßig deaktiviert und empfiehlt, es niemals für User-Input zu nutzen.

$expr — Expressive Queries:

$expr erlaubt komplexere Aggregations-Ausdrücke und kann ähnliche Bypass-Pattern erzeugen, wenn aus User-Input zusammengebaut.

$lookup und Sub-Queries:

$lookup joint mit anderen Collections. Wenn der/die Angreifer:in $lookup injizieren kann, lassen sich Daten aus anderen Collections in das Ergebnis ziehen — analog zu SQL UNION-Based-Injection.

Schutz-Patterns

1. Strikte Schema-Validation auf Body-Ebene.

Bevor User-Input überhaupt in die Query fließt, wird er validiert: alle Felder müssen primitive Typen sein, keine Objekte/Operator-Felder.

Express mit Zod:

JavaScript zod-validation.js
import { z } from 'zod';

const LoginSchema = z.object({
  username: z.string().min(1).max(100),
  password: z.string().min(1).max(200),
}).strict();
// .strict() lehnt unbekannte Properties ab — und Operator-Objekte sind keine Strings

app.post('/login', async (req, res) => {
  const parsed = LoginSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).send('Invalid input');
  }
  const { username, password } = parsed.data;
  // username und password sind GARANTIERT Strings — kein Operator-Bypass
  const user = await db.users.findOne({ username, password });
  // ...
});

Schema-Validation ist die wirksamste und einfachste Schutz-Schicht.

2. Mongoose strictQuery: true.

Wenn Mongoose das ORM ist, hilft die strictQuery-Option:

JavaScript mongoose-strict.js
mongoose.set('strictQuery', true);

// Mit strictQuery werden Felder, die nicht im Schema sind,
// aus der Query entfernt
User.findOne({ username: 'admin', $where: '...' });
// $where wird ignoriert, weil nicht im Schema

Stand 2026 ist strictQuery: true Default in Mongoose 7+. Aber: das schützt nur vor unbekannten Top-Level-Feldern, nicht vor Operator-Werten innerhalb erlaubter Felder. Schema-Validation bleibt nötig.

3. Operator-Stripping-Middleware.

Ein häufiges Pattern: Middleware, die alle $-Felder aus Request-Bodies entfernt:

JavaScript strip-dollar-middleware.js
function sanitizeMongo(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;
  if (Array.isArray(obj)) return obj.map(sanitizeMongo);
  const result = {};
  for (const key in obj) {
    if (key.startsWith('$')) continue;  // Operator-Felder entfernen
    if (key.includes('.')) continue;     // Dot-Notation entfernen
    result[key] = sanitizeMongo(obj[key]);
  }
  return result;
}

app.use((req, res, next) => {
  req.body = sanitizeMongo(req.body);
  req.query = sanitizeMongo(req.query);
  next();
});

Die Library express-mongo-sanitize macht das fertig — sehr verbreitet in Express-Setups. Stripping ist defensive Schicht; Schema-Validation bleibt die primäre.

4. Explizite Typen in der Query.

JavaScript explicit-string-cast.js
// Sicher: explizit String-Konvertierung
const username = String(req.body.username);
const password = String(req.body.password);
const user = await db.users.findOne({ username, password });
// String() macht aus Objekten "[object Object]" — Match scheitert

Schnelle Verteidigung, aber nicht ausreichend als alleinige Schicht — bessere Option ist Schema-Validation.

5. $where global deaktivieren.

In MongoDB-Konfiguration:

JavaScript disable-where.js
// mongod.conf
security:
  javascriptEnabled: false

Damit ist $where server-seitig deaktiviert — auch wenn ein:e Angreifer:in es einschleusen kann, läuft kein JS.

CouchDB

CouchDB nutzt JSON-basierte Queries mit Map-Reduce-Views. Injection-Pattern:

  • Server-Side JavaScript-Functions in Views — bei User-konfigurierbaren Views potenziell Code-Eval.
  • Mango Queries (CouchDB 2.0+) ähnlich zu MongoDB-Queries — gleiche Operator-Manipulation möglich.
  • _design-Documents mit User-Input — Code-Injection in Views.

Schutz: User-Input niemals direkt in View-Definitionen oder Mango-Queries. Schema-Validation, Allow-List für Query-Operatoren.

Elasticsearch

Elasticsearch hat eigene Injection-Klassen:

Query-DSL-Injection:

JavaScript elasticsearch-injection.js
// Schadhaft
const query = JSON.parse(`{
  "query": {
    "match": {
      "name": "${userInput}"
    }
  }
}`);
// Wenn userInput Anführungszeichen enthält, bricht die Struktur

// Sicher: strukturiertes Objekt bauen
const query = {
  query: { match: { name: userInput } }
};

Painless-Script-Injection:

Painless ist Elasticsearchs eingebaute Skript-Sprache. In Aggregations und script_score-Queries verwendbar. Wenn User-Input in ein Painless-Skript fließt:

JSON painless-injection-risk.json
{
  "query": {
    "script_score": {
      "script": {
        "source": "doc['score'].value * ${userMultiplier}"
      }
    }
  }
}

Wenn userMultiplier aus User-Input kommt und ungesichert eingebaut wird, kann ein:e Angreifer:in beliebiges Painless ausführen — RCE-nahe Möglichkeit. Schutz: params-Feld für User-Werte:

JSON painless-with-params.json
{
  "query": {
    "script_score": {
      "script": {
        "source": "doc['score'].value * params.multiplier",
        "params": { "multiplier": 2.5 }
      }
    }
  }
}

params werden als Daten behandelt — kein Code-Eval.

Path-Manipulation in URLs:

Elasticsearch-API ist REST. URL-Parameter (index, type) sollten nicht aus User-Input ohne Allowlist konstruiert werden.

Redis

Redis hat sein eigenes Risiko-Profil:

Command-Injection in Redis-Clients:

Wenn ein Redis-Client raw-Commands aus User-Input baut, kann eine eingeschleuste Newline-Sequenz mehrere Commands triggern (Redis-Protokoll ist line-basiert):

JavaScript redis-newline-injection.js
// Schadhaft (hypothetisch — moderne Clients schützen)
client.set(`session:${userId}`, userData);
// Wenn userData newlines enthält, könnte Protokoll-Injection möglich sein

Moderne Redis-Clients (ioredis, node-redis, redis-py) protokollieren binär und sind dagegen geschützt. Schwachstellen historisch in selbstgebauten Clients.

LUA-Script-Injection:

Redis kann LUA-Skripte ausführen (EVAL). Wenn User-Input ungesäubert in ein LUA-Skript fließt — Code-Injection:

JavaScript lua-injection.js
// Schadhaft
client.eval(`return redis.call('GET', '${userKey}')`, 0);

// Sicher: LUA-KEYS statt String-Konkat
client.eval(`return redis.call('GET', KEYS[1])`, 1, userKey);

Module-Funktionen:

Redis-Module (RedisJSON, RediSearch) bringen eigene Query-Sprachen mit. Bei RediSearch z. B. Filter-Syntax, die mit User-Input gebaut werden kann — analog zu NoSQL-Injection.

Test-Strategien

Manuelle Tests:

Klassisches Test-Payload-Set für NoSQL-Injection in Login-Endpunkten:

JSON nosql-test-payloads.json
// Login-Bypass
{ "username": "admin", "password": { "$ne": "x" } }
{ "username": "admin", "password": { "$gt": "" } }
{ "username": "admin", "password": { "$regex": ".*" } }

// Daten-Discovery
{ "username": { "$ne": "x" }, "password": { "$ne": "x" } }

// $where-Test (wenn aktiviert)
{ "$where": "this.role === 'admin'" }

Automatisierte Tools:

  • NoSQLMap — analog zu sqlmap, aber für MongoDB/CouchDB.
  • Burp Suite Pro mit NoSQL-Plugin.
  • OWASP ZAP mit NoSQL-Add-On.

Statische Analyse:

  • Semgrep-Regeln für findOne-mit-direktem-Body, $where-Nutzung.
  • CodeQL mit JavaScript-Security-Pack.
  • eslint-plugin-security für Node.js-spezifische Patterns.

Code-Review-Pattern:

Suche nach:

  • req.body oder req.query direkt in findOne, findAndUpdate, aggregate.
  • $where-Verwendung im Code.
  • Ungetypte Function-Argumente, die in Mongo-Queries fließen.

Reale Vorfälle

Diaspora (2018) — MongoDB-Injection in der Open-Source-Social-Network-Plattform. Operator-basierter Bypass von Auth-Checks. Patch innerhalb von Tagen.

Reddit-Mod-Tools (2022) — interne Tools mit MongoDB-Backend; Bug-Bounty-Report über Operator-Manipulation in Filter-Funktionen. Auszahlung im vierstelligen Bereich.

MongoDB Atlas — Misconfiguration-Wellen statt direkter Injection: viele MongoDB-Instanzen sind offen im Internet, ohne Authentifizierung. Massendurchsuchungen seit 2017 (MongoDB-Ransomware-Wellen). Strenggenommen keine Injection, aber verwandtes Risiko-Cluster.

npm-Pakete mit NoSQL-Injection-CVEs — diverse kleinere Libraries, die Mongo-Queries aus User-Input bauen, haben über die Jahre CVEs gesammelt. Z. B. mongo-sanitize selbst hatte einmal eine Bypass-Schwäche.

Im Vergleich zu SQL-Injection sind NoSQL-Vorfälle weniger spektakulär, aber regelmäßig in Pentest-Reports. Wer mit MongoDB arbeitet und Body-Parser ungeschützt nutzt, hat hohes Risiko.

Besonderheiten

Operator-Felder sind das Kernproblem

SQL hat eine separate Query-Sprache; MongoDB nutzt JSON-Objekte. Das Problem: wenn der Body-Parser User-JSON-Objekte direkt entgegennimmt und das ORM sie als Query nutzt, ist die Trennung zwischen Daten und Operator-Anweisungen verloren. Schema-Validation reduziert User-Input strikt auf erwartete Daten-Typen.

$where ist faktisch deprecated

MongoDB selbst empfiehlt seit Jahren, $where nicht mehr zu nutzen — wegen Performance und Security. Seit MongoDB 4.4 ist es opt-in (security.javascriptEnabled). Wer $where in seinem Code findet: refactor zu nativer Query oder Aggregation.

Mongoose strictQuery in 6 → 7 → 8

Mongoose hat die Default-Einstellung mehrfach gewechselt. In Mongoose 6 war strictQuery per Default false; seit Mongoose 7 ist es true; Mongoose 8 macht es noch strikter. Bei Upgrades: Tests prüfen, ob alte Queries weiter funktionieren.

express-mongo-sanitize hat ältere Versionen mit Bugs

Die populäre Library hatte historisch Bypass-Schwächen — z. B. wenn Operator-Felder als Werte (nicht als Keys) auftauchten. Aktuelle Versionen sind gehärtet. Defense-in-Depth: nicht alleine darauf vertrauen.

GraphQL über MongoDB: doppelte Injection-Schicht

Wenn GraphQL-Backend mit MongoDB als Storage, sind beide Schichten Injection-relevant: GraphQL-Query-Manipulation (siehe GraphQL-Sicherheit Kap 18) PLUS Mongo-Operator-Injection im Resolver. Beide getrennt zu prüfen.

Aggregation-Pipeline-Injection ist subtiler

MongoDB-Aggregation-Pipelines ($match, $group, $lookup, ...) können ähnliche Probleme haben wie normale Find-Queries. Bei User-konfigurierbaren Filtern im Aggregation-Modus oft übersehen.

Elasticsearch Painless ist Sandboxed — aber nicht risikofrei

Painless läuft in einer Sandbox, die OS-Calls blockiert. Aber: Daten-Exfiltration über Aggregations-Ergebnisse, Information-Disclosure über Fehlermeldungen, DoS über Endlos-Schleifen sind weiter möglich. params-Feld konsequent nutzen.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Injection (SQL/NoSQL/Cmd)

Zur Übersicht