FlawOpen

flawopen.com/Справочник/NoSQL-инъекция MongoDB: когда входные данные меняют запрос

NoSQL-инъекция MongoDB: когда входные данные меняют запрос

Руководство по безопасности баз данных

MongoDB не выполняет SQL, поэтому склейка SQL-строк здесь ни при чём. NoSQL-инъекция возможна, если приложение принимает недоверенный вложенный объект вместо скалярного значения и передаёт его в фильтр MongoDB. Это ошибка проверки входных данных приложения, а не CVE сервера MongoDB.

Простыми словами: значение становится правилом

Представьте форму, где просят имя, но сотрудник принимает в поле целый набор инструкций. База выполняет инструкции вместо сравнения одного имени. Проверяйте ожидаемый тип значения и создавайте правило поиска самостоятельно.

Граница доверия: от JSON-запроса до фильтра MongoDB

Фильтр запроса
Документ BSON, который MongoDB трактует как сравнения полей и, если они явно заданы, как операторы запроса.
Внедрение оператора
Приложение передаёт контролируемую пользователем структуру туда, где ожидалось одно литеральное значение.
Проверка скаляра
Проверка типа, длины и допустимого формата до того, как входные данные повлияют на операцию с базой.
Проекция
Выбранный сервером список полей, ограничивающий случайное раскрытие данных.

Как возникает ошибка

1

Конечная точка ожидает скаляр

Контракт API определяет username как строку, но JSON-парсер также может вернуть массив, объект, boolean или null.

2

Приложение пропускает проверку типа

Обработчик напрямую вставляет разобранное значение в созданный сервером фильтр; объект остаётся структурой запроса, а не простой строкой.

3

MongoDB интерпретирует переданную структуру

Если вложенный документ содержит операторы запроса, условие может отличаться от задуманного точного сравнения. Затронутые записи зависят от запроса и проверок авторизации приложения.

4

Ответ определяет масштаб раскрытия

Возвращаемые поля и число записей зависят от проекции, конечной точки и привилегий учётной записи БД. Само по себе это не доказывает обход аутентификации или доступ ко всей базе.

Область и подтверждения

Официальные рекомендации MongoDB для драйверов описывают эту границу, когда конечная точка преобразует непроверенный JSON в BSON и использует его как фильтр. Здесь показана ошибка уровня приложения. Руководство не утверждает, что уязвимы все установки MongoDB, не указывает CVE сервера и не содержит инструкции по обходу аутентификации.

Уязвимый и защищённый шаблоны 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);
  }
});

Защищённый путь отклоняет поля нестрокового типа до обращения к базе данных, не принимает фильтр от клиента, задаёт фиксированный ключ фильтра в коде приложения, возвращает только выбранные поля и проверяет хеш пароля после поиска пользователя. В примере z — это Zod, users — коллекция MongoDB, а argon2 — настроенная библиотека хеширования паролей; создание сессии намеренно оставлено за рамками примера.

Проверки исправления

Первичные источники

Связанные руководства по безопасности:Открыть каталог безопасности →
См. также SQL-инъекции (CWE-89): как они работают и как их предотвратить в любом языке — flawopen.com SQL Injection при числовых ID: риск? Что такое параметризованный запрос? Защищает ли Prisma $queryRaw от SQL-инъекций? Безопасна ли интерполяция в Rails where()? Защищает ли Sequelize query() от SQL-инъекций? Защищает ли SQLAlchemy text() от SQL-инъекций?