banner
wuhang2003

Zwh's Blog

ZH/EN | 一个人不在计算机专业却时不时就想折腾计算机相关东西的咸鱼

破事水 | 關於資料庫被黑的這麼一檔子事兒

背景#

在 10 號晚上 11 點的時候群內有相當一部分人都發現後台需要重新初始化了,而 Mongo 數據庫被清空,只留下一封勒索信。有先發案例,其他成員,包括我也迅速查了一下,果然我也跟著中槍了,為此 Innei 還專門發了個安全預警

勒索信原始文本:(From wibus

We delete all databases, but download a copy to our server. The only way of recovery is you must send 0.01 BTC to bc1qmaacz9fdvnkujqlf8m547mzzh0l5t0ajn699th. You have until 48 hours to pay or data will be inaccessible. Once paid please email incomings99112@onionmail.com with code: xxxxxx and we will recover your database. please read https://paste.sh/UY6_vtGL#THGqRdL9oQqUc-28RPDOWSbB for more information.

當然 mx-space 作為一個優秀的 CMS 系統,自帶了自動備份,每天凌晨 1 點自動備份當日數據。所以我直接進文件管理把當天的備份文件,還有附近幾日的落鴿下載下來,一方面方便恢復,另一方面分享落鴿到群裡,看群裡有啥說法。

分析#

毫無疑問,既然被黑那證明有漏洞,畢竟俗話說蒼蠅不叮無縫的蛋。就群裡的幾位被黑的用戶(包括我)的描述而言被刪庫的幾個都有共同點:沒有服務商 / VPS 的防火牆,Mongo 容器開啟映射端口且默認直接映射到 0.0.0.0(即公網可直接訪問),數據庫也無鑒權機制,所以被 gank 了。

解決方案與後期措施#

關閉不必要的映射#

在最開始的安全預警中 Innei 提到了一點,就是關閉不必要的映射。

像之前版本的 Docker Compose 文件中 mongo 和 Redis 各有一個端口映射,由於不指定 IP,Docker 的默認行為會直接將其映射到 0.0.0.0,即暴露到公網。而實際上考慮到 mongo 和 Redis 和主容器在一個網絡下,連接沒有問題,所以完全可以直接丟掉端口映射。如下是丟掉端口映射後的部分內容。

  mongo:
    container_name: mongo
    image: mongo
    volumes:
      - ./data/db:/data/db
    networks:
      - app-network
    restart: always
  redis:
    image: redis
    container_name: redis
    networks:
      - app-network
    restart: always

networks:
  app-network:
    driver: bridge

上防火牆#

其次,考慮到這是端口暴露產生的問題,所以也給服務器安裝了個 UFW 攔個端口。當然,安裝完後需要給服務器 SSH 端口和 1Panel 端口放行後再啟動防火牆,不然連不了服務器 / 上不了面板就尷尬了(

sudo apt update
sudo apt install ufw
sudo ufw allow 22/tcp # 如果SSH運行在非標準端口,需要將上述命令中的22端口替換為對應的SSH端口。
sudo ufw allow 8090/tcp # 放開1Panel系統端口,把8090換為面板的端口
sudo ufw enable # UFW,啟動!

1Panel 也有對應的防火牆功能,在啟動 UFW 之後就可以直接在面板管理 UFW 了,非常適合擺爛方便管理。

降低容器權限#

感謝屑timo的建議與指導。操作很簡單,但我 Linux 了解的不夠深入,折騰的時候百度了 114514 回命令(

首先直接改 Compose 配置文件,加一行user: node,如下(文件節選)

version: '3.8'

services:
  app:
    container_name: mx-server
    image: innei/mx-server:latest
    command: bash ./docker-run.sh
    environment:
      - TZ=Asia/Shanghai
      - NODE_ENV=production
      - ALLOWED_ORIGINS
      - JWT_SECRET
      - ENCRYPT_KEY
      - ENCRYPT_ENABLE
    volumes:
      - ./data/mx-space:/root/.mx-space
    ports:
      - '2333:2333'
    depends_on:
      - mongo
      - redis
    links:
      - mongo
      - redis
    networks:
      - app-network
    restart: always
    user: node
    healthcheck:
      test:
        [
          'CMD',
          'curl',
          '-f',
          'http://127.0.0.1:2333/api/v2/ping'
        ]
      interval: 1m30s
      timeout: 30s
      retries: 5
      start_period: 30s

加了這條約束之後,容器內會指定以 node 用戶(UID 為 1000)運行命令,而宿主機的進程歸屬也是用的 UID 1000(有可能系統沒有 UID 為 1000 的用戶),不再是默認的 root 了,安全風險也小了許多。

但是,容器以 UID 1000 運行了,容器內數據被扔在了/home/node/下,而數據文件夾的歸屬還在 root 手上,所以還得同時修改容器配置文件中的容器內數據位置以及宿主機中對應映射文件夾的歸屬。而這些都是 Linux 的基本操作了,不想命令行也可以直接在面板的文件管理中改,就不再額外贅述了。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。