FlawOpen

flawopen.com/Référence/Injection NoSQL MongoDB : quand une entrée modifie la requête

Injection NoSQL MongoDB : quand une entrée modifie la requête

Guide de sécurité des bases de données

MongoDB n’exécute pas SQL : la concaténation de chaînes SQL n’est donc pas en cause. Une injection NoSQL reste possible si l’application accepte un objet imbriqué non fiable à la place d’une valeur scalaire et le transmet à un filtre MongoDB. Il s’agit d’un défaut de validation des entrées de l’application, pas d’une CVE du serveur MongoDB.

En clair : une valeur devient une règle

Imaginez qu’un formulaire demande un nom, mais que l’agent accepte un ensemble d’instructions dans ce champ. La base suit les instructions au lieu de comparer un nom. Vérifiez le type attendu et construisez vous-même la règle de recherche.

Frontière de confiance : du JSON de la requête au filtre MongoDB

Filtre de requête
Document BSON interprété par MongoDB comme des comparaisons de champs et, le cas échéant, des opérateurs de requête.
Injection d’opérateur
L’application transmet une structure contrôlée par l’utilisateur à un emplacement où elle attendait une valeur littérale unique.
Validation scalaire
Vérifier le type, la longueur et le format autorisé avant que l’entrée puisse influer sur une opération de base de données.
Projection
Liste de champs choisie côté serveur pour limiter l’exposition accidentelle de données.

Comment le défaut se produit

1

Le point de terminaison attend un scalaire

Le contrat de l’API définit username comme une chaîne, mais un parseur JSON peut aussi produire des tableaux, objets, booléens et null.

2

L’application omet la validation du type

Le gestionnaire insère la valeur analysée directement dans un filtre créé par le serveur : l’objet reste une structure de requête au lieu de devenir une chaîne littérale.

3

MongoDB évalue la structure fournie

Si le document imbriqué contient des opérateurs de requête, le prédicat peut différer de la comparaison exacte prévue. Les enregistrements concernés dépendent de la requête et des contrôles d’autorisation de l’application.

4

La réponse détermine l’exposition

Les champs et le nombre d’enregistrements renvoyés dépendent de la projection, du point de terminaison et des privilèges du compte de base. Cela ne prouve pas à lui seul un contournement d’authentification ni un accès à toute la base.

Portée et éléments probants

La documentation officielle des pilotes MongoDB décrit cette frontière lorsqu’un point de terminaison convertit du JSON non validé en BSON et l’utilise comme filtre. Ce guide illustre ce défaut côté application. Il ne prétend pas que toutes les installations MongoDB sont vulnérables, ne cite aucune CVE serveur et ne fournit pas de recette de contournement d’authentification.

Exemples vulnérable et renforcé en Node.js

VULNERABLE — UNVALIDATED VALUE ENTERS FILTER
app.post("/users/lookup", async (req, res, next) => {
  try {
    // The route expects a string, but req.body.username is untrusted JSON.
    const user = await users.findOne({ username: req.body.username });
    res.json(user ? { username: user.username } : null);
  } catch (error) {
    next(error);
  }
});
HARDENED — VALIDATE SHAPE, BUILD FILTER, VERIFY HASH
const loginSchema = z.object({
  username: z.string().trim().min(1).max(128),
  password: z.string().min(1).max(1024)
}).strict();

app.post("/login", async (req, res, next) => {
  try {
    const parsed = loginSchema.safeParse(req.body);
    if (!parsed.success) return res.sendStatus(400);

    const { username, password } = parsed.data;
    // The application owns the filter key; input supplies only a string value.
    const user = await users.findOne(
      { username },
      { projection: { _id: 1, username: 1, passwordHash: 1 } }
    );
    const passwordMatches = user &&
      await argon2.verify(user.passwordHash, password);
    if (!passwordMatches) return res.sendStatus(401);

    return res.sendStatus(204); // Session creation is application-specific.
  } catch (error) {
    next(error);
  }
});

Le parcours renforcé rejette les champs qui ne sont pas des chaînes avant tout accès à la base, n’accepte aucun filtre fourni par le client, construit une clé de filtre fixe dans le code de l’application, ne renvoie que les champs sélectionnés et vérifie le hachage du mot de passe après la recherche de l’utilisateur. L’exemple suppose que z désigne Zod, users la collection MongoDB et argon2 une bibliothèque de hachage configurée ; la création de session est volontairement hors périmètre.

Vérifications du correctif

Sources primaires

Consultez les guides de sécurité associés :Ouvrir le répertoire de sécurité →
À voir aussi Injection SQL (CWE-89) : fonctionnement et prévention dans chaque langage — flawopen.com Un ID numérique peut-il aussi provoquer une injection SQL ? Qu'est-ce qu'une requête paramétrée ? Prisma $queryRaw protège-t-il contre les injections SQL ? L’interpolation dans where() de Rails est-elle sûre ? Sequelize query() protège-t-il contre les injections SQL ? SQLAlchemy text() protège-t-il contre les injections SQL ?