NoSQL 注入以及如何避免它们
NoSQL注入漏洞是使用NoSQL数据库的Web应用程序中的错误。此Web应用程序安全问题使恶意方可以绕过身份验证,提取数据,修改数据,甚至获得对应用程序的完全控制。NoSQL注入攻击是缺乏数据清理的结果。
与传统的SQL注入类似,NoSQL注入只是众多注入攻击中的一种。它们被设计为利用不使用SQL的现代数据库。NoSQL(不仅是SQL)一词用于描述使用不太严格的结构的数据库,并且可以指许多不同类型的数据库,包括那些使用诸如键值,键文档,列族或图形之类的模型数据库。
尽管NoSQL数据库引擎具有不同的结构,并且不支持SQL语句和SQL查询,但它们仍允许用户执行查询。它们不支持一种标准化语言,因此查询语言取决于实现方式:数据库(例如MongoDB,Redis,Google Cloud Datastore等),语言(例如Python,PHP等)和框架(例如Node)。 js,Angular)。但是,NoSQL查询通常基于JSON,并且可以包含用户输入。如果未对此输入进行消毒,则它们很容易受到注入。
PHP应用程序中的MongoDB注入示例
为了了解如何构造NoSQL查询以及它如何容易受到注入攻击,我们将重点介绍最流行的NoSQL数据库:MongoDB,并将使用PHP访问它。这是访问MongoDB进行身份验证的代码段的简单示例。
$username = $_POST['username'];
$password = $_POST['password'];
$connection = new MongoDB\Client('mongodb://localhost:27017');
if($connection) {
$db = $connection->test;
$users = $db->users;
$query = array(
"user" => $username,
"password" => $password
);
$req = $users->findOne($query);
}
如您所见,在此示例中,用于身份验证的用户名和密码来自POST请求,然后直接在查询中使用。与其他类型的注入类似,恶意用户可能会提供欺骗数据库的NoSQL注入有效负载。
要成功执行MongoDB注入,只要攻击者提供以下恶意输入数据作为POST请求就足够了:
username[$eq]=admin&password[$ne]=foo
查询操作符[$ne]表示不相等。因此,结果查询将找到用户名为admin且密码不是foo的第一条记录。如果将此代码用于身份验证,则攻击者将以admin用户身份登录。
可以以类似的方式使用更多的操作符,例如[$lt]
和[$gt]
以及[$regex]
。通过按顺序尝试组合并评估结果,正则表达式甚至可以使攻击者枚举上述情况下的所有用户。
高级攻击和JavaScript注入
MongoDB查询支持常用的运算符$where
,它引入了严重的NoSQL攻击(包括JavaScript对象)的可能性。
例如,开发人员可能希望以$where
以下方式使用运算符来访问特定用户的记录:
$query = array('$where' => 'this.name === \''.$name.'\'');
在这种情况下,攻击者可能会提供以下空字符串比较技巧$name
:
'; return '' == '
结果,查询将变为:
"$where": "this.name === ''; return '' == ''"
攻击者将收到整个用户列表。
由于$where
操作符实际上是JavaScript代码,因此攻击者还可以传递包含任意JavaScript的恶意字符串,例如:
'; while(true){}'
本示例创建一个永无止境的循环,并导致拒绝服务攻击。
如何避免NoSQL注入
为了避免NoSQL注入,您必须始终将用户输入视为不受信任。您可以执行以下操作来验证用户输入:
- 使用 sanitization library 。例如,mongo-sanitize或mongoose。
- 如果找不到适合您环境的库,请将用户输入转换为所需的类型。例如,将用户名和密码转换为字符串。
- 在MongoDB的情况下,切勿在用户输入中使用
where
,mapReduce
或group
运算符,因为这些运算符使攻击者能够注入JavaScript,因此比其他运算符更加危险。为了加强安全性,在mongod.conf如果可能的话,设置javascriptEnabled
为false
。 - 此外,请始终使用最小特权模型:以尽可能低的特权运行您的应用程序,以便即使被利用,攻击者也无法访问其他资源。
