本教程的早期版本由Melissa Anderson编写。
介绍
MongoDB,也称为Mongo,是许多现代 Web 应用程序中使用的开源文档数据库。它被归类为NoSQL 数据库,因为它不依赖于传统的基于表的关系数据库结构。相反,它使用具有动态模式的类 JSON 文档。
MongoDB 默认不启用身份验证,这意味着任何有权访问安装数据库的服务器的用户都可以不受限制地添加和删除数据。为了保护此漏洞,本教程将引导您创建管理用户并启用身份验证。然后,您将进行测试以确认只有该管理用户有权访问数据库。
先决条件
要完成本教程,您将需要以下内容:
- 运行 Ubuntu 20.04 的服务器。此服务器应具有非 root 管理用户和使用 UFW 配置的防火墙。按照我们针对 Ubuntu 20.04 的初始服务器设置指南进行设置。
- MongoDB 安装在您的服务器上。本教程使用 MongoDB 版本4.4进行了验证,但它通常也适用于旧版本的 MongoDB。要在您的服务器上安装 Mongo,请按照我们关于如何在 Ubuntu 20.04 上安装 MongoDB 的教程进行操作。
第 1 步 – 添加管理用户
自3.0版本发布以来,MongoDB 守护进程被配置为仅接受来自本地 Unix 套接字的连接,并且不会自动向更广泛的 Internet 开放。但是,默认情况下仍禁用身份验证。这意味着可以访问安装了 MongoDB 的服务器的任何用户也可以完全访问数据库。
作为保护此漏洞的第一步,您将创建一个管理用户。稍后,您将启用身份验证并以此管理用户身份连接以访问数据库。
要添加管理用户,您必须首先连接到 Mongo shell。因为身份验证被禁用,您可以使用该mongo
命令执行此操作,无需任何其他选项:
- mongo
Mongo shell 提示上方会有一些输出。因为您还没有启用身份验证,这将包括一个警告,指出未为数据库启用访问控制,并且对数据和数据库的配置的读写访问不受限制:
OutputMongoDB shell version v4.4.0
. . .
2020-06-09T13:26:51.391+0000 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2020-06-09T13:26:51.391+0000 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
. . .
>
在您启用身份验证后,这些警告将消失,但就目前而言,它们意味着任何可以访问您的 Ubuntu 服务器的人也可以控制您的数据库。
为了说明,运行 Mongo 的show dbs
命令:
- show dbs
此命令返回服务器上每个数据库的列表。但是,启用身份验证后,列表会根据 Mongo 用户的角色或它对某些数据库的访问级别而更改。但是,由于身份验证被禁用,它将无限制地返回系统上当前的每个数据库:
Outputadmin 0.000GB
config 0.000GB
local 0.000GB
在此示例输出中,仅显示默认数据库。但是,如果您的系统上有任何保存敏感数据的数据库,任何用户都可以使用此命令找到它们。
作为缓解此漏洞的一部分,此步骤的重点是添加管理用户。为此,您必须首先连接到admin
数据库。这是有关用户的信息(如用户名、密码和角色)的存储位置:
- use admin
Outputswitched to db admin
MongoDB 随附了许多可用于管理数据库的基于 JavaScript 的 shell 方法。其中之一是db.createUser
方法,用于在运行该方法的数据库上创建新用户。
启动db.createUser
方法:
- db.createUser(
此方法要求您为用户指定用户名和密码,以及您希望用户拥有的任何角色。回想一下,MongoDB 将其数据存储在类似 JSON 的文档中。因此,当您创建新用户时,您所做的只是创建一个文档,将适当的用户数据保存为单独的字段。
与 JSON 中的对象一样,MongoDB 中的文档以花括号 ( {
and }
)开头和结尾。要开始添加用户,请输入左花括号:
注意:db.createUser
在您输入右括号之前,Mongo 不会将该方法注册为完整的。在您这样做之前,提示将从大于号 ( >
) 变为省略号 ( ...
)。
- {
接下来,输入一个user:
字段,将您想要的用户名作为双引号中的值,后跟一个逗号。以下示例指定用户名AdminSammy,但您可以输入任何您喜欢的用户名:
- user: "AdminSammy",
接下来,输入一个pwd
以passwordPrompt()
方法作为其值的字段。当您执行该db.createUser
方法时,该passwordPrompt()
方法将提示您输入密码。这比替代方法更安全,替代方法是像输入用户名一样以明文形式输入密码。
注意:该passwordPrompt()
方法仅与 MongoDB 4.2及更新版本兼容。如果您使用的是旧版本的 Mongo,那么您必须以明文形式写出密码,类似于您写出用户名的方式:
- pwd: "password",
请务必在此字段后面加上逗号:
- pwd: passwordPrompt(),
然后输入您希望管理用户具有的角色。因为您正在创建一个管理用户,所以您至少应该授予他们userAdminAnyDatabase
对admin
数据库的角色。这将允许管理用户创建和修改新用户和角色。因为管理用户在admin
数据库中有这个角色,这也将授予它对整个集群的超级用户访问权限。
此外,以下示例还授予管理用户readWriteAnyDatabase
角色。这使管理用户能够读取和修改集群中任何数据库上的数据,除了主要供内部使用的config
和local
数据库:
- roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
然后,输入一个右大括号来表示文档的结尾:
- }
然后输入一个右括号来关闭并执行该db.createUser
方法:
- )
总之,您的db.createUser
方法应该如下所示:
> db.createUser(
... {
... user: "AdminSammy",
... pwd: passwordPrompt(),
... roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
... }
... )
如果每一行的语法正确,该方法将正确执行,并提示您输入密码:
OutputEnter password:
输入您选择的强密码。然后,您将收到添加用户的确认信息:
OutputSuccessfully added user: {
"user" : "AdminSammy",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
},
"readWriteAnyDatabase"
]
}
之后,您可以退出 MongoDB 客户端:
- exit
此时,您的用户将被允许输入凭据。但是,在您启用身份验证并重新启动 MongoDB 守护程序之前,他们不需要这样做。
第 2 步 – 启用身份验证
要启用身份验证,您必须编辑mongod.conf
MongoDB 的配置文件。启用它并重新启动 Mongo 服务后,用户仍然可以在不进行身份验证的情况下连接到数据库。但是,在他们提供正确的用户名和密码之前,他们将无法读取或修改任何数据。
使用您喜欢的文本编辑器打开配置文件。在这里,我们将使用nano
:
- sudo nano /etc/mongod.conf
向下滚动以找到注释掉的security
部分:
. . .
#security:
#operationProfiling:
. . .
通过删除井号 ( #
)取消注释此行:
. . .
security:
#operationProfiling:
. . .
然后添加authorization
参数并将其设置为enabled
. 完成后,这些行应如下所示:
. . .
security:
authorization: enabled
. . .
请注意,该security:
行开头没有空格,而该authorization:
行缩进了两个空格。
添加这些行后,保存并关闭文件。如果您曾经nano
打开过该文件,请按CTRL + X
、Y
、来打开ENTER
。
然后重新启动守护程序以使这些新更改生效:
- sudo systemctl restart mongod
接下来,检查服务的状态以确保它正确重启:
- sudo systemctl status mongod
如果restart
命令成功,您将收到指示该mongod
服务处于活动状态且最近已启动的输出:
Output● mongod.service - MongoDB Database Server
Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2020-06-09 22:06:20 UTC; 7s ago
Docs: https://docs.mongodb.org/manual
Main PID: 15370 (mongod)
Memory: 170.1M
CGroup: /system.slice/mongod.service
└─15370 /usr/bin/mongod --config /etc/mongod.conf
Jun 09 22:06:20 your_host systemd[1]: Started MongoDB Database Server.
验证守护程序已备份并运行后,您可以测试您添加的身份验证设置是否按预期工作。
第 3 步 – 测试身份验证设置
要开始测试您在上一步中添加的身份验证要求是否正常工作,请先在不指定任何凭据的情况下进行连接,以验证您的操作确实受到限制:
- mongo
现在您已启用身份验证,您之前遇到的任何警告都不会出现:
OutputMongoDB shell version v4.4.0
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("5d50ed96-f7e1-493a-b4da-076067b2d898") }
MongoDB server version: 4.4.0
>
通过show dbs
再次运行命令确认您的访问是否受到限制:
- show dbs
回忆第 1 步,您的服务器上至少有几个默认数据库。但是,在这种情况下,该命令不会有任何输出,因为您尚未作为特权用户进行身份验证。
由于此命令不返回任何信息,因此可以肯定地说身份验证设置按预期工作。如果没有首先进行身份验证,您也将无法创建用户或执行其他特权任务。
继续并退出 MongoDB shell:
注意:不是exit
像您之前在第 1 步中那样运行以下命令,另一种关闭 shell 的方法是按CTRL + C
。
- exit
接下来,通过运行以下mongo
命令以该用户身份进行连接,确保您的管理用户能够正确进行身份验证。此命令包含-u
标志,该标志位于您要连接的用户名之前。请务必将AdminSammy替换为您自己的管理用户的用户名。它还包括-p
标志,它会提示您输入用户的密码,并指定admin
为创建指定用户名的身份验证数据库:
- mongo -u AdminSammy -p --authenticationDatabase admin
出现提示时输入用户的密码,然后您将进入 shell。到达那里后,show dbs
再次尝试发出命令:
- show dbs
这一次,因为您已正确进行身份验证,该命令将成功返回服务器上当前所有数据库的列表:
Outputadmin 0.000GB
config 0.000GB
local 0.000GB
这确认身份验证已成功启用。
结论
通过完成本指南,您已经设置了一个管理 MongoDB 用户,您可以使用该用户来创建和修改新用户和角色,以及管理您的 MongoDB 实例。您还配置了 MongoDB 实例,要求用户在与任何数据交互之前使用有效的用户名和密码进行身份验证。
有关如何管理 MongoDB 用户的更多信息,请查看关于该主题的官方文档。您可能也有兴趣了解有关身份验证如何在 MongoDB 上工作的更多信息。
此外,如果您计划远程与您的 MongoDB 实例交互,您可以按照我们关于如何在 Ubuntu 20.04 上为 MongoDB 配置远程访问的指南进行操作。