V5627. OWASP. Possible NoSQL injection. Potentially tainted data is used to create query.
Анализатор обнаружил использование непроверенных данных из внешнего источника для формирования запроса к NoSQL базе данных. Это может стать причиной NoSQL-инъекции в случае, если данные скомпрометированы.
Инъекции выделены в отдельную категорию рисков в OWASP Top 10 Application Security Risks 2021: A3:2021-Injection.
Рассмотрим пример:
public IFindFluent<BsonDocument, BsonDocument> Authentication()
{
String log = Request.Form["login"];
String pass = Request.Form["password"];
String filter = "{$where: \"function() {" +
$"return this.login=='{log}' && this.password=='{pass}'"+
";}\"}";
return collection.Find(filter);
}
Метод 'Authentication' ищет запись пользователя в NoSQL базе данных MongoDB по логину и паролю. Для этого создается строка 'filter', содержащая JavaScript код. С её помощью будут фильтроваться результаты поиска. Аналогом этой операции в SQL будет следующий запрос: SELECT * FROM collection WHERE login = @log AND password = @pass.
Для формирования фильтра используются значения строк 'log' и 'pass', полученные из внешнего источника. Подобное использование непроверенных данных позволяет злоумышленнику внедрить вредоносный код внутрь запроса.
Например, здесь злоумышленник может отправить вместо ожидаемого значения 'pass' строку следующего вида:
"-1' || this.login == 'admin"
Тогда обращение к базе данных может выглядеть так:
{$where: "function()
{
return this.login == 'doesn't matter'
&& this.password == '-1'
|| this.login == 'admin';
}"}
В таком случае запрос вернёт данные аккаунта администратора.
Для защиты от инъекций NoSQL базы предоставляют инструменты параметризированного создания запросов.
Пример создания безопасного запроса:
public IFindFluent<BsonDocument, BsonDocument> Authentication()
{
String log = Request.Form["login"];
String pass = Request.Form["password"];
var filter = Builders<BsonDocument>.Filter.Eq("login", log)
& Builders<BsonDocument>.Filter.Eq("password", pass);
return collection.Find(filter);
}
Здесь фильтр создается при помощи специального класса 'Builders'. За счёт этого запрос будет параметризованным и внешние данные не смогут повлиять на логику фильтрации.
Анализатор также считает источниками небезопасных данных параметры методов, доступных из других сборок. Более подробно эта тема раскрыта в заметке "Почему важно проверять значения параметров общедоступных методов".
Рассмотрим пример:
public class MongoDBRep
{
public void DeleteItemsByCounter(string count)
{
DeleteMany(count);
}
private void DeleteMany(string count)
{
var filter = "{$where:\"function(){return this.count == "+count+";}\"}";
collection.DeleteMany(filter);
}
}
Здесь потенциально заражённые данные из параметра 'count' передаются в метод 'DeleteMany', внутри которого они без проверки используются для удаления записей из базы данных.
Злоумышленник может сформировать запрос следующего вида:
{$where: "function()
{
return this.count == -999
|| 1 == 1;
}"}
Исполнение этого запроса приведёт к удалению всех документов базы данных, независимо от значения поля 'count'.
В этом случае рекомендуется защититься тем же способом, что был приведён ранее.
Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.). |
Данная диагностика классифицируется как:
|