漏洞现象
在部署好 botfront,并创建了管理员账号之后,第二天发现账号消失了。 我本以为是本地目录权限问题,导致 mongodb 没有将数据写入磁盘。 但是,修改了本地目录权限之后,这个问题又出现了。
感觉出大问题了。
查看 mongodb 日志
通过 docker logs 查看了 mongodb 镜像的日志。
{"t":{"$date":"2023-07-10T12:33:33.424+00:00"},"s":"I", "c":"-", "id":20883, "ctx":"conn158","msg":"Interrupted operation as its client disconnected","attr":{"opId":1499371}}
{"t":{"$date":"2023-07-10T12:33:33.425+00:00"},"s":"I", "c":"NETWORK", "id":22944, "ctx":"conn158","msg":"Connection ended","attr":{"remote":"68.183.135.77:51070","uuid":"b8cbcfc7-e33e-48a8-bcee-cb8b23ecc91c","connectionId":158,"connectionCount":7}}
{"t":{"$date":"2023-07-10T12:33:33.428+00:00"},"s":"I", "c":"NETWORK", "id":22944, "ctx":"conn159","msg":"Connection ended","attr":{"remote":"68.183.135.77:51076","uuid":"1fb1b912-85ab-4105-9464-4ad251578595","connectionId":159,"connectionCount":6}}
从 IP 看是一个美国 digital ocean 机房的机器发起的恶意行为。
因为 botfront 安装的 mongodb 默认开放了外网端口,27017, 且没有设置访问账号密码。 所以很快被黑客扫描到了。于是被清空了所有数据。
对应的现象就是管理员账号消失了。
连接 mongodb
安装 mongodb cli
sudo apt install mongodb-clients
本地验证了一下,确实没有设置访问账号密码:
$ mongo
MongoDB shell version v3.6.8
connecting to: mongodb://127.0.0.1:27017
可以看到一个警告信息:
{"t":{"$date":"2023-07-09T07:06:29.183+00:00"},"s":"W", "c":"CONTROL", "id":22120, "ctx":"initandlisten","msg":"Access control is not enabled for the database. Read and write access to data and configuration is unrestricted","tags":["startupWarnings"]}
解决方法一:不对外开发 27017 端口
修改 botfront 生成的 docker compose 配置文件。
将 mongodb 镜像对应的端口
由
'27017:27017'
改成
'27017'
这样就可以保证 docker 网络组内可以访问 mongodb,而通过宿主机外网则无法访问。
注意要使新的 compose 配置生效,需要使用
docker compose stop mongo
docker compose up -d mongo
而不是
docker compose start mongo
start 依然使用的是旧配置。
通过
docker container ls
就能看到具体的端口变化:
前: 0.0.0.0:27017->27017/tcp, :::27017->27017/tcp botfront-mongo
后: 0.0.0.0:32768->27017/tcp, :::32768->27017/tcp botfront-mongo
然后再通过开发机远程连接服务器上的 mongodb,确实再也访问不了。
但是这个方案有个巨大的缺陷,就是 botfront 每次在命令行中 enable 一个新 project 时, 这个 docker compose 文件会被重新生成,然后再次恢复那个漏洞。
解决方法二:屏蔽端口
根本的解决方案有两个:
- 修改 iptables。但是我对这个不熟悉,最好找专业的运维去修改
- 修改云服务器 web 管理后台,直接在那个网络规则上修改。例如阿里云、腾讯云的网络端口配置
为何在 UFW 里屏蔽不了 27017 端口
虽然通过 UFW 屏蔽了 27017 端口,但是实际测试发现,端口依然可以访问。
$ sudo ufw status
Status: active
To Action From
-- ------ ----
80/tcp ALLOW Anywhere
27017/tcp DENY Anywhere
27017/udp DENY Anywhere
80/tcp (v6) ALLOW Anywhere (v6)
27017/tcp (v6) DENY Anywhere (v6)
27017/udp (v6) DENY Anywhere (v6)
参考
https://askubuntu.com/questions/652556/uncomplicated-firewall-ufw-is-not-blocking-anything-when-using-docker
即 docker 会绕过 ufw 直接修改 iptables 规则。
The problem was using the -p flag on containers.
It turns out that Docker makes changes directly on your iptables, which are not shown with ufw status.
Possible solutions are:
Stop using the -p flag. Use docker linking or docker networks instead.
Bind containers locally so they are not exposed outside your machine:
docker run -p 127.0.0.1:8080:8080 ...
If you insist on using the -p flag, tell docker not to touch your iptables by disabling them in /etc/docker/daemon.json and restarting:
{ "iptables" : false }
I recommend option 1 or 2. Beware that option 3 has side-effects, like containers becoming unable to connect to the internet.
$ sudo iptables -L
Chain DOCKER (3 references)
ACCEPT tcp -- anywhere 172.20.0.5 tcp dpt:27017
Chain ufw-user-input (1 references)
DROP tcp -- anywhere anywhere tcp dpt:27017
DROP udp -- anywhere anywhere udp dpt:27017
docker compose 文件端口配置,中 “80:80” 与 “80” 的区别
在 Docker Compose 文件中,端口配置语法通常采用 "HOST:CONTAINER" 的格式,其中 "HOST" 指的是主机上的端口,而 "CONTAINER" 指的是容器内部的端口。这个语法意味着 Docker 会将主机上的端口映射到容器内的端口。
- "80:80" 表示将主机上的 80 端口映射到容器内部的 80 端口。这意味着当您在主机上访问 80 端口时,请求将被 Docker 转发到容器内的 80 端口。这种配置方式是最常见的端口映射方式。
- "80" 表示将容器内部的 80 端口暴露给主机,但不会将主机上的任何端口映射到容器内部的端口。这意味着您可以在容器内部运行服务,但无法从主机上访问该服务。这种配置方式适用于只需要在容器内部运行服务的场景。
查看合集
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式