发布于

给你的 Mongodb 和 Redis 增加密码认证

作者
  • 姓名
    Twitter

前言

最近需要使用 Redis 数据库,安装的时候发现原来 Redis 同 Mongodb一样,默认是不需要密码的,想了下是测试数据库,存的又只是用户 cookies,就并没有在意。同时使用的 Mongodb 虽然默认也是不需要密码验证的,但因为其官方的 Docker Hub 页面上有比较清晰的添加用户认证的说明,在安装的时候就顺便增加了权限认证。

但没有想到的是这一无意举动竟然给服务器带来了风险,服务器险些变成肉鸡,这也侧面说明了一件事,每天在互联网中有无数的端口扫描工具在日夜不停的寻找漏洞目标,稍有不慎,我们的服务器就会沦为肉鸡,任人宰割。

本文就将讲述如何给默认不包括用户认证的 Mongodb 和 Redis 数据库,增加用户认证,如果你也在使用无安全措施的 Mongodb 或者 Redis,在看到此文后,请务必根据本文内容添加安全措施,或者通过防火墙控制访问 IP。

问题发现

今天突然发现 Setapp 中那款叫 TablePlus 的数据库可视化管理软件增加了对 Mongodb 的支持,便想把之前用的 Robo 3T 给卸载掉(主要是界面不好看),换成 TablePlus,因为在增加了对 Mongodb 的支持后,TablePlus 基本上已经支持了所有主流数据库:

tableplus-ui.png

在添加数据库时,因为其同样支持 Redis,就把在使用的 Redis 数据库也添加了进去,不添加不要紧,一添加才发现情况不对:

redis-hacked.png

除了用于缓存存储的db1之外,还多了一个db0,虽然本人对 Redis 可以说是完全不了解,但这个db0中的内容稍微懂脚本的人就能看出来,是在下载某地址的一个脚本并执行,于是我查询了这个 IP 的归属,并打开了这个脚本文件,查看了一下内容:

redis-hacker-ip.png

IP 地址是一个 IDC 的,熟悉主流 VPS 厂商的应该知道,这个运营商就是 GigsGigsCloud,是一个比较常见的主机商,应该是攻击者将脚本放在自己购买的VPS服务器上。

至于脚本内容,打开一看,我才发现又是挖矿脚本,截取一些关键内容如下:

  • 一些参数: hacker-shell.png

  • 清理其他探矿脚本: hacker-shell2.png

下面还有很长,就不截图了,看来同行太多,抢机器也很辛苦啊。

  • 脚本下载: hacker-shell3.png

  • 甚至还控制自己的 CPU 占用避免被发现 hacker-shell4.png

  • 试图添加攻击者的公钥 hacker-shell5.png

还有很多内容,本人也不是很懂 shell 语言,也只能大约知道是在干啥,就不贴图了,总之我们知道这是一个挖矿脚本,并且试图完全控制我们的服务器。

不过本人检查了服务器运行情况,一切正常,相关脚本并没有运行,攻击者的公钥也没有添加到authorized_keys文件中,原因应该是由于本人的 Redis 是运行在 Docker 容器中,这倒也省了本人解决问题的时间,下面直接进入本文的主题,那就是给没有保护措施的 Mongodb 和 Redis 加一道锁。

给 Mongodb 增加安全认证

Docker 安装

安装方式

官方镜像默认是不包括安全策略的,但可以通过增加环境参数的方式在创建容器的时候创建超级用户,如果添加了用户名和密码的参数,那么 Mongodb 将默认以 --auth 即认证方式运行:

具体可参考官方 Docker Hub 页面

我们参考官方页面可以直接运行如下命令:

docker run -d -p 27017:27017 --name mongo \
    -e MONGO_INITDB_ROOT_USERNAME=mongoadmin \
    -e MONGO_INITDB_ROOT_PASSWORD=your_password \
    -v mongo_db:/data/db \
    -v mongo_configdb:/data/configdb \
    mongo

官方提供的示例中包括了 --network 的选项这里省略了,如果你需要添加进特定子网,可以在创建容器后使用 docker network connect 连接。

通过上面的命令我们就能创建一个初始超级用户为 mongoadmin 的需要认证才能访问的 Mongodb。

Mongodb 的基本使用

通过 Docker 安装的 Mongodb,要使用 mongo cli,需要使用docker exec命令,具体如下:

docker exec -it mongo bash

当然这里的mongo,要换成你自己起的容器名,运行上面命令之后,我们就进入了容器内部,这时直接输入mongo就能进入到 Mongodb 的命令行模式,这里提供几个常用操作,一般应用基本足够应付:

用户认证

我们需要切换到 admin 数据库下使用超级用户认证:

use admin
db.auth('mongoadmin','your_password')

回车后显示1,就说明认证成功。

创建数据库

比如我们要创建一个名叫 test 的数据库,直接使用 use test即可完成创建并切换至 test 数据库

创建用户

创建数据库后,如果不添加用户,我们无法使用该数据库,所以我们必须添加一个针对该数据库的用户,需要使用如下命令:

db.createUser(
  {
    user: "test",
    pwd: "test12345",
    roles: [ { role: "readWrite", db: "test" } ]
  }
)

运行以上命令将创建一个能够对 test 数据库进行读写的 test用户,密码为 test12345,如果创建成功,会提示成功创建用户。

整个基本流程如下图所示:

mongo-basic.png

之后我们可以通过 mongodb://test:test12345@服务器IP:27017/test 来连接数据库。

非 Docker 安装

如果你并未使用 Docker 安装 Mongodb,并且已经安装好了无安全认证的 Mongodb 又不想重新安装,可以通过以下步骤添加安全认证。

本部分使用 Ubuntu 18.04 进行测试,初始状态是直接使用 apt install mongodb 命令安装了 Mongodb,并且打开了远程访问,这会是很多人将 Mongodb 用于测试的基本流程

打开远程访问以及认证模式

我们需要修改 /etc/mongodb.conf 文件,如果你已经在使用 Mongodb 应该已经修改过 bind_ip了,这里就只需增加 auth=true即可。 mongo-config.png

  • bind_ip127.0.0.1 改为 0.0.0.0
  • auth=true 前的 # 去掉使之生效。

之后使用 service mongodb restart 重启 Mongodb,这时我们将无法再不使用用户名密码直接访问 Mongodb 数据库了。

增加超级用户

首先使用 mongo进入 Mongodb 的命令行模式,这时用户列表为空,我们需要创建一个超级用户,虽然我们已经开启了认证模式,但由于此时用户列表为空,我们不需认证就能创建一个超级用户:

use admin
db.createUser({
   user: "mongoadmin",
   pwd: "your-password",
   roles: [ { role: "userAdminAnyDatabase", db: "admin" }]
  })

之后的步骤请参考上文,完全一致。

Redis增加安全认证

与 Mongo 类似,如果 Redis 发现服务器暴露在互联网上,则会将其 bind127.0.0.1,禁止非本机之外的访问,同样可以通过简单的将127.0.0.1修改为0.0.0.0开放外网访问。使用 Docker 安装的 Redis 如果未添加特别参数,将默认开放外网访问。

如果你的 Redis 是非 Docker 安装,又暴露在了互联网上,将是非常危险的,经了解要防范可能的攻击,可以进行的安全措施主要包括以下几点:

  • 避免公网访问
  • 更换默认的 6379 端口
  • 使用非 root 用户运行 Redis
  • 开启密码验证并设置复杂密码
  • 禁用或重命名危险命令

本文将只添加密码验证,如果有更高的安全需求,可以参考下方参考文档以及官方文档进行设置。

通过 Google 搜索 Redis 入侵 关键字,发现一篇遇到的问题与本文开头类似,甚至内容风格也与本文类似,但更加详细的文章,有兴趣的朋友请点击这里访问。

Docker 安装

Redis 官方 Docker Hub 页面提供的内容价值有限,并未提供任何有关访问控制的信息,我们可以直接运行如下命令启动一个 Redis 容器:

docker run --name some-redis -d -p 6379:6379 redis redis-server --appendonly yes

之后我们可以直接通过连接服务器 IP 的 6379 端口访问 Redis 服务器。通过这种方式使用Redis,将无法自定义设置,因为在容器中是没有 redis.conf 这个文件的。官方 Docker Hub 表示如果需要使用自定义的 redis.conf 文件,需要使用 Dockerfile 添加或者使用文件夹绑定:

redis-docker-conf.png

考虑到我们使用 Docker 的目的就是方便,本人不建议使用这些复杂的方式,如果仅需使用密码验证,在创建 Docker 容器的时候,添加额外参数即可实现。

开启密码验证

在创建 Docker 容器时,添加requirepass参数可以设置为需要密码访问。

我们使用的命令如下:

docker run -d -p 6379:6379 \
--name some-redis \
-v redis_data:/data \
redis \
redis-server --appendonly yes \
--requirepass "your_password"

其中的 some-redis 更换成你想要起的容器名, redis-server --appendonly yes 大意是开启持久化配置,未详细了解,这里我们还顺便对数据进行了持久化储存,使用 volume 保存容器 /data 目录的内容。

之后我们使用 Redis 数据库时,必须输入密码,否则没有任何操作权限。

  • 使用 Redis-cli的方式

通过 -a 直接添加密码

docker exec -it some-redis redis-cli -a 'your_password'

或者进入 redis-cli 后再进行认证,看命令行提示,官方应该是更推荐这种方式:

docker exec -it some-redis redis-cli
auth 'your_password'

redis-password-auth.png

非 Docker 安装

如果你已经直接通过 apt 或者 yum 等命令将 Redis 安装到了系统中,并且没有设置密码验证,需要通过修改 redis.conf 文件来增加密码验证。

Redis 官方提供的 redis.conf 文件注释真的是非常非常的详细,即使我们对 Redis 完全不了解,也能够通过参考官方说明进行修改。

该文件的路径经测试在 /etc/redis/redis.conf,看网上的指引一般都说在/etc/redis.conf,请自行测试。

开放外部访问

vim /etc/redis/redis.conf

之后找到 bind 127.0.0.1 ::1这一行,在下面添加一行,内容为bind 0.0.0.0,如下图所示: redis-config-bind.png

保存退出后,重启 Redis 服务器:

service redis-server restart

这样设置之后就可以从任意 IP 访问我们的 Redis 服务器了。

增加密码访问

继续对 redis.conf 文件进行编辑,找到内容为 # requirepass foobared 的一行,将前面的注释 # 去掉,同时将 foobared 修改为你要使用的密码。

redis-config-passwd.png

注意官方文档的特别提示:由于 Redis 速度很快,所以外部用户可以以高达每秒15万次的速度尝试,所以推荐我们使用一个强密码避免被轻松破解。

设置完成后,保存退出,重启 Redis 服务器:

service redis-server restart

这样设置之后再访问我们的 Redis 服务器就必须使用密码验证了。

外部连接方式

在设置了密码后,外部连接 Redis 需要使用以下方式:

使用 redis-cli 连接

远程连接使用如下命令:

redis-cli -h 服务器IP -p 6379

参考上文内容可知,可通过在命令最后增加 -a 'your_password',或者连接后使用 auth 'your_password'的方式,这里不再详述。

Node.js 中连接

在引入 redis 的 npm 包之后,连接 Redis 服务器的命令格式如下:

redis.createClient(port,host,config)

port 表示端口,一般为 6379 host 表示服务器,填写服务器 IP config 为配置文件,我们需要将密码添加到这里,形式为{ auth_pass: 'your_password' }

其他方式连接请自行搜索。

参考文档

本文在撰写过程中,部分参考了以下内容,向作者表示感谢:

  1. Mongo Official Docker Hub Page

  2. mongodb 远程访问配置

  3. mongodb操作之用户篇

  4. Redis Official Docker Hub Page

  5. 事件分析 | 一起攻击者利用 Redis 未授权访问漏洞进行新型入侵挖矿事件

  6. 记一个 Redis 安全漏洞和 Redis 安全规范

  7. Docker安装官方Redis镜像并启用密码认证 实践笔记

  8. redis: set a password for redis