MongoDB中的NoSQL注入:漏洞机制和防范措施

在使用数据库的系统安全性方面,需要特别注意的一项是SQL注入。SQL注入是一种通过外部意外输入而执行恶意SQL语句的漏洞。当在操作SQL数据库时,如果实现中将用户输入不正确地验证和转义并嵌入到SQL查询中,则会发生SQL注入。

使用NoSQL数据库可以避免SQL注入的发生,但同时要注意NoSQL注入的问题。

本文将以使用MongoDB实现系统的示例为基础,解释NoSQL注入。

NoSQL与SQL的区别。SQL是Structured Query Language的简称,是用于操作和获取关系型数据库数据的标准编程语言。

NoSQL是指采用与关系型数据库不同的数据模型的数据库的统称。像MongoDB和Redis这样的数据库属于NoSQL分类。

SQL 是一种编程语言,而 NoSQL 是指不使用 SQL 的非关系数据库。

什么是NoSQL注入攻击?NoSQL注入是指在NoSQL数据库中发生的注入漏洞。在NoSQL中,不使用SQL语句来操作数据,而是使用自定义的查询语言和API。由于不同类型的数据库有不同的操作方法,注入的发生模式也不是统一的。

然而,还有一些共同的措施可以采取。

    • パラメータ化されたクエリを使用する

 

    リクエストパラメータが不正な形式だった場合は処理を行わない

通过进行诸如此类的行动,可以降低风险。

脆弱实现的示例

使用环境

    • プログラミング言語

Node.js

データベース

MongoDB

ライブラリ

mongoose
express

我们将以一个简单的Web服务登录用API为例来进行解释。数据操作将使用MongoDB操作库“mongoose”。

用户模型

username: String
password: String

终端点:POST /登录

发送JSON数据

{
  username: 'john',
  password: 'hoge',
}

案例1:评估表达式的改写

app.post('/login', async (req, res) => {
  const username = req.body.username;
  const password = req.body.password;
  const users = await User.find({
    $where: `this.username === '${username}' && this.password === '${password}'`
  });
  if (users.length === 0) {
    res.json({
      message: 'Failed to log in.'
    });
    return;
  }
  res.json({
    message: `Successfully logged in as ${users[0].username}`
  });
});
$where: `this.username === '${username}' && this.password === '${password}'`

在这种实现情况下,通常会按照以下方式执行。

$where: `this.username === 'john' && this.password === 'hoge'`

如果用户名或密码中包含单引号字符串,可以添加新的条件语句。

$where: `this.username === 'john' && this.password === '' || this.username === 'admin'`

当您插入这样的字符串时,即可无需密码以其他用户身份登录。

作为应对措施,可以停止使用$where,并将其替换为以下参数化查询。

const users = await User.find({
  username: username,
  password: password,
})

情景2:增加操作员

app.post('/login', async (req, res) => {
  const username = req.body.username;
  const password = req.body.password;
  const users = await User.find({
    username: username,
    password: password,
  });
  if (users.length === 0) {
    res.json({
      message: 'Failed to log in.'
    });
    return;
  }
  res.json({
    message: `Successfully logged in as ${users[0].username}`
  });
});

如果实施如此,通常会执行以下操作。

const users = await User.find({
  username: 'john',
  password: 'hoge',
});

如果将这个用户名和密码以对象形式而不是字符串形式接收的话,

const users = await User.find({
  username: 'john',
  password: {
    $ne: 'dummy'
  },
});

$ne是用于MongoDB的比较运算符。它表示”不等于”,因此即使密码不匹配,登录也会成功。

对策方面,以下的修改方法是有效的。

    • パラメータの型がオブジェクト型ではないことを確認する

 

    パラメータの型が適切な型である(例では文字列型)ことを確認する

总结在使用像MongoDB等NoSQL数据库的情况下,我们需要找出可能发生注入的查询语言或API的地方,并进行适当的输入检查。

在MongoDB的情况下,您可以通过以下方法来防止:

    • パラメータ化されたクエリの使用($whereを使用しない)

 

    パラメータの型のバリデーション

最後AeyeScan是一种SaaS型的Web应用程序漏洞扫描平台。由于可以快速准确地进行Web扫描,因此被许多企业用作Web应用程序扫描的内部工具。

如果对我们在本次解释中介绍的MongoDB的NoSQL注入感兴趣的话,您可以通过试用来测试。有关AeyeScan的详细信息,请访问:https://www.aeyescan.jp

bannerAds