MongoDB基础4——安全与身份认证

2017年1月,正值新年伊始,一些黑客组织发动了一场针对MongoDB数据库的攻击,全球有数以万计的MongoDB中招,它们的数据库被整个完整得清空,然后新建了一个名为“WARNING”的数据库,索要赎金。然而令人瞠目结舌的是,这些所谓的“攻击”甚至不能叫做攻击,因为这些中招的MongoDB正处于“裸奔”的状态!

所谓“裸奔”,就是说MongoDB直接对公网开放所有的读写权限,更严重的是,MongoDB默认配置甚至不需要用户名密码就能直接登录进行管理,也就是说,任何人都可以对MongoDB进行读、写、甚至直接毁灭(Drop)。而本次攻击的,正是这样的一些MongoDB。

这次攻击正突显了MongoDB的使用者安全意识的缺乏,竟然让自己的数据库对外网开发,并且还不设置密码,被攻击了也是活该。

所以,在学习MongoDB之初,就请一定不要忘记,在部署MongoDB到服务器时,一定一定要注意安全设置!!!!


1.启动服务器的两种方式

1.1 不安全的启动方式

前面提到,启动MongoDB的命令是:

mongod --dbpath ../data/db

不过,需要注意的是,这种方式是不安全的!为什么说是不安全的?原因是通过这种方式启动MongoDB,如果没有绑定可访问的IP,那么就相当于把自己的数据库直接暴露在公网中,也就是所谓的“裸奔”。因此,在部署生产环境的时,一定不能用这种方式来启动。

下图是开启了一个shell终端来访问数据库,命令是mongo <mongodb所在服务器的IP或域名>:27017;默认端口号是 27017,如果你修改过MongoDB服务的端口号,则将 27017 替换为你修改的端口号即可。

Paste_Image.png

1.2 安全的启动方式

要以安全的方式启动MongoDB数据库,需要在启动命令中加入 --auth 参数;一旦加上此参数,登录服务器就必须是认证的用户。

mongod --auth --dbpath ../data/db

使用 --auth 参数重新启动MongoDB后,再通过shell查看所有数据库,就会提示需要登录了:

Paste_Image.png

需要说明的是,如果你只是在MongoDB服务所在的本机中进行操作,是不会被禁止的。启动shell的命令直接用mongo 即可,不需要在后面加上IP和端口号。


2.MongoDB的身份验证

我们在启动MongoDB后,查看所有的数据库,会发现我们什么都还没做,有已经有两个特殊的数据库: adminlocal

事实上,这两个数据库正是MongoDB进行身份验证所需的。我们可以将这两个数据库中的用户看作是管理员,或者说是超级用户;经过认证后,管理员可以对任何数据库进行读写操作,并执行某些特殊命令,如listDataBasesshutdown [1]


2.1 增加一个管理员

如果MongoDB服务是在本机,则直接操作即可。但如果MongoDB在远程,则需要:

  • 远程的MongoDB使用不安全的方式启动,然后在本地进行操作
  • 或者在远程的MongoDB中设置允许访问的IP:mongod --bind_ip 127.0.0.1,10.118.4.27 [2]

我们以第一种方式,即让远程MongoDB服务以不安全方式启动:

mongod --dbpath ../data/db

MongoDB启动后,我们通过shell连接到此服务器,并执行:

> use admin
switched to db admin
>
> db.addUser("root", "123456")
{ "n" : 0, "connectionId" : 2, "err" : null, "ok" : 1 }
{
        "user" : "root",
        "readOnly" : false,
        "pwd" : "34e5772aa66b703a319641d42a47d696",
        "_id" : ObjectId("58c20b105991fbda9129bad9")
}

在创建了管理员后,我们让远程服务以安全模式重启,然后在本地用刚刚创建的管理员帐户登录:

> use admin
> db.auth("root", "123456")

需要注意的是,一定要先切换到admin数据库,否则会如下图红框内所示,仍无法管理:

Paste_Image.png

在实际使用中,不要设置** 123456 **之类的弱密码!设置的密码最起码要满足以下几个条件

  • 位数在8位以上
  • 包含大小写字母、数字
  • 建议包含一些特殊符号,如 $ @ #

2.2 设置管理员只读权限

db.addUser() 命令中,最后一个参数为 readOnly,如果设置为 true ,即表示此用户只有读权限、没有写权限,操作如下:

db.addUser("reader", "123456", true)

这样创建的管理员就只能读取数据库了。


2.3 更改管理员权限

addUser() 命令既可以用来创建新用户,也可用于更改原用户的权限、设置新密码等。

比如,我们要将上面创建的 read 用户的密码改为 654321 ,则:

db.addUser("reader", "654321", true)

再比如,我们要将上面创建的 read 用户的设置为读写权限 ,则:

db.addUser("reader", "654321", false)

3.管理管理员

是的,我们要知道有多少管理员、他们的权限是怎样的,我们需要管理这些管理员。


3.1 身份验证的原理

MongoDB的管理员用户是存储在system,users中的,其结构信息如下:

{
    user     :  username,
    readonly :  true,
    pwd      :  password hash   
}

其中,password hash 是基于 username 和密码生成散列值 [1]

因此,从本质上说,管理员的身份信息也是存储在一个数据库中;那么我们要管理管理员,操作方法也是一样的,只是要对 system.users 进行操作。

既然管理员身份信息是存储在system.users中,我们在开发过程中,也应避免将网站的数据库命名为 system


3.2 删除一个管理员

很简单地,要删除一个管理员用户(如删除 read 用户),只需要执行 remove 命令即可:

db.system.users.remove({"user", "read"})

[1] 资料来自 《MongoDB权威指南》,图字01-2013-6738号,人民邮电出版社
[2] 参考资料: MongoDB限制内网访问的方法

推荐阅读更多精彩内容