对话机器人 Rasa(十四):Botfront 自带的 MongoDB 端口问题

文章目录

    漏洞现象

    在部署好 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 文件会被重新生成,然后再次恢复那个漏洞。

    解决方法二:屏蔽端口

    根本的解决方案有两个:

    1. 修改 iptables。但是我对这个不熟悉,最好找专业的运维去修改
    2. 修改云服务器 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 端口暴露给主机,但不会将主机上的任何端口映射到容器内部的端口。这意味着您可以在容器内部运行服务,但无法从主机上访问该服务。这种配置方式适用于只需要在容器内部运行服务的场景。

    查看合集

    📖 对话机器人 Rasa 中文系列教程

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式