Selector Injection Attack в MongoDB

Сегодня узнал, что в мире MongoDB существует такая штука, как «Selector Injection Attack».

Если упростить, то представим, что есть приложение на Express/Koa с Mongoose и в одном из эндпоинтов надо проверить, валидны ли учётные данные пользователя. Допустим мы делаем это так:

await User.findOne({
  email: req.body.email,
  password: req.body.password,
});

(Да, пароль должен быть захеширован, но это пример.)

Код выглядит невинно, но это не так. Если клиент отправит такое тело запроса:

{
  email: "[email protected]",
  password: { "$ne": null }
}

то будут проблемы.

MongoDB интерпретирует это как запрос пользователя с указанным адресом почты и любым ненулевым паролем. Если это логика аутентификации — пользователя успешно залогинит.

То есть, даже если мы не в мире SQL, всё равно нужно санитизировать пользовательский ввод. И есть несколько способов.

Можно делать это вручную — удалять все $-подобные операторы и точки из ключей объектов. См. express-mongo-sanitize.

В Mongoose же можно включить опцию sanitizeFilter, которая оборачивает ключи фильтра в $eq, делая такие инъекции невозможными. Подробнее в блоге разработчика Mongoose.