[2026 Remastered · 03] 从 MongoDB 未授权裸奔到零信任加固:原稿语法勘误、authSource 认证陷阱与 Docker 防火墙绕过防御
🛸 站长重制导读(Anti Gravi's Remaster Note)
本文是 「来时路 · 2026 重制企划(3/12)」 的第 3 篇,对应本站 2019 年 12 月 18 日发布的 《Mongodb未授权访问漏洞修复》(
CID: 16)。2019 年的原稿记录了为新搭建的 MongoDB 创建
admin管理员与业务库账号、并在/etc/mongod.conf中开启security.authorization: enabled的标准加固流程,且在第四节详细梳理了 RBAC 最小权限角色(read/readWrite/dbOwner等),安全意识非常到位。站在 2026 年回看并逐行审视原稿代码,我们筛查出了 4 处实操细节勘误与生产架构盲区:从代码块里漏掉注释符導致直接复制执行报语法错误、改完配置漏写重启指令,到无数研发踩坑的
authSource(认证数据库)与业务数据库分离机制,以及云原生时代最危险的 Docker-p 27017:27017绕过宿主机防火墙惨案。
一、 2019 原稿 (CID: 16) 四大细节筛查与勘误
我们先回顾 2019 年原稿第 3 节给出的核心操作代码:
// 2019 原稿第 48~54 行原始代码块:
Mongo>use admin; # 进入admin数据库
Mongo>db.createUser({ user: 'root', pwd: '654321', roles: [ 'root']}) # 创建用户,设置密码为654321,角色为root
Mongo>db.auth("root","654321") 验证进入数据库,若返回1则为认证通过
Mongo>use test; # 为数据库创建鉴权账号时需先进入该数据内
Mongo>db.createUser( {user: "test",pwd: "123456",roles: [ { role: "dbOwner", db: "test" } ]}) # 为test数据库创建鉴权用户test,密码为123456,角色为数据库所有者,详细数据库角色可见下方
# 2019 原稿第 59~62 行修改配置文件:
vim /etc/mongod.conf
security:
authorization: enabled #开启Mongodb登录认证
对照真实生产环境,原稿存在以下四处需要修正与补完的关键点:
| 编号 | 2019 原稿 (CID: 16) 写法与表述 |
真实执行后果 / 潜在隐患 | 2026 Remastered 勘误与加固方案 |
|---|---|---|---|
| 1. Shell 注释符混入 JS 终端 + 第 51 行漏写注释符 | 行尾用 # 进入admin数据库 作注释,且第 51 行 db.auth("root","654321") 验证进入数据库... 连 # 都漏了 |
MongoDB Shell(无论是旧版 mongo 还是现代 mongosh)底层都是 JavaScript 引擎,只支持 // 或 /* */ 注释!若读者整行复制带有 # 或裸中文的行粘贴进终端,会当场抛出 SyntaxError: Unexpected character '#' |
在 mongosh 中统一使用标准 JS 注释 // |
2. 仅开 authorization 却未锁死 net.bindIp |
原稿仅展示了在 /etc/mongod.conf 中添加 security.authorization: enabled(且末尾漏写了 systemctl restart mongod) |
虽然 MongoDB 3.6+ 默认绑定 127.0.0.1,但很多安装教程会指导用户先改成 bindIp: 0.0.0.0;若仅开启密码认证而将 27017 端口暴露在公网,依然会面临全天候自动化字典爆破与 CVE 预认证漏洞扫描;此外改完 mongod.conf 必须重启或重载服务才会生效 |
遵循纵深防御:网络层强制绑定内网 IP(如 bindIp: 127.0.0.1,10.10.0.6) + 开启 authorization: enabled + 执行 sudo systemctl restart mongod |
3. 缺失 authSource(认证库)概念说明 |
原稿在 admin 库创建了 root,在 test 库创建了 test,但未说明连接字符串的写法差异 |
MongoDB 的账号是与创建时所在的数据库(use <db>)强绑定的!如果研发用 admin 下创建的账号去连 app_db(写成了 mongodb://admin_user:[email protected]:27017/app_db),MongoDB 会默认去 app_db 里找该用户,当场报错 Authentication failed! |
明确区分:连接目标库与 ?authSource=admin 认证源库;现代最佳实践建议将所有用户统一创建在 admin 库下管理,通过 roles: [{ role: "readWrite", db: "app_db" }] 跨库授权 |
4. 传统 mongo Shell 退役与弱口令示例 |
使用 Mongo> 提示符与 123456 / 654321 示例密码 |
自 MongoDB 6.0 起,传统的 C++ mongo 客户端已被彻底移除,全面替换为 mongosh;且 SCRAM-SHA-1 逐渐被更抗暴力破解的 SCRAM-SHA-256 取代 |
全面采用 mongosh 语法,显式启用 SCRAM-SHA-256 与高熵随机密钥 |
二、 生产环境血泪教训:为什么开了 ufw / firewalld 防火墙,Docker 里的 MongoDB 还是被黑客勒索了?
在近年来的 MongoDB 未授权访问被删库勒索(留下一张 READ_ME_TO_RECOVER_YOUR_DATA 表索要比特币)事故中,占比最高的原因已经不再是宿主机 RPM/APT 直接安装,而是 Docker 容器化部署时的两个致命误区:
误区 1:使用 docker run -p 27017:27017 mongo 直接穿透宿主机防火墙
很多运维以为宿主机开了 ufw 或 firewalld 默认拒绝入站端口就万事大吉,随手敲了一句:
# ❌ 极度危险:将容器 27017 绑定到宿主机 0.0.0.0:27017!
docker run -d --name mongo -p 27017:27017 mongo:8.0
底层真相:Docker 守护进程在配置 -p 27017:27017 时,会直接在 Linux 内核 Netfilter 的 PREROUTING / DOCKER 链 插入 DNAT 转发规则,它的优先级高于 ufw 和 firewalld 所在的 INPUT 链!也就是说,除非你在云厂商安全组拦截,否则 -p 27017:27017 会直接无视宿主机防火墙,把未开启认证的 MongoDB 裸露在公网之上!
✅ 正确写法(强制绑定宿主机回环或指定内网网卡 IP):
# 仅允许本机或同一内网网段访问,绝不暴露给公网网卡:
docker run -d --name mongo \
-p 127.0.0.1:27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin_root \
-e MONGO_INITDB_ROOT_PASSWORD="$(openssl rand -base64 24)" \
mongo:8.0 --auth
三、 2026 生产级 MongoDB 7.0 / 8.0 认证加固完整标准流程
1. 使用现代 mongosh 初始化管理员与最小权限业务账号
在首次启动 MongoDB(此时仅监听 127.0.0.1 本机回环)后,使用 mongosh 登录并借助 本地回环例外机制(Localhost Exception) 创建账号:
// 1. 进入本机 mongosh 终端:
// $ mongosh "mongodb://127.0.0.1:27017"
// 2. 切换至 admin 数据库创建全局超级管理员(仅限 DBA 运维使用,严禁配置给业务代码!)
use admin;
db.createUser({
user: "dba_admin",
pwd: passwordPrompt(), // 交互式安全输入密码,避免明文留在历史记录中
roles: [
{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "dbAdminAnyDatabase", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" }
],
mechanisms: ["SCRAM-SHA-256"]
});
// 验证管理员认证(mongosh 返回 { ok: 1 } 表示通过)
db.auth("dba_admin", passwordPrompt());
// 3. 为业务库 order_service 创建专属最小权限账号(注意:只给 readWrite,不给 dbOwner 防止业务代码误删库/删索引!)
use order_service;
db.createUser({
user: "order_app",
pwd: passwordPrompt(),
roles: [
{ role: "readWrite", db: "order_service" }
],
mechanisms: ["SCRAM-SHA-256"]
});
[!TIP]
角色选型升级建议(对比 2019 原稿):
2019 年原稿第 53 行给业务账号test分配了dbOwner角色。在现代生产规范中,dbOwner拥有dropDatabase(删库)和修改系统集合的最高权限;对于常规微服务应用,应严格遵循最小权限原则只授予readWrite角色,仅在执行数据库 Schema 迁移时才临时使用管理账号。
2. 加固 /etc/mongod.conf 并重启验证
编辑 /etc/mongod.conf(注意 YAML 严格使用 2 空格缩进,禁混入 Tab):
net:
port: 27017
# 严禁写 0.0.0.0!仅绑定本地回环与受控内网业务网卡 IP
bindIp: 127.0.0.1,10.10.0.6
security:
# 强制开启基于角色的访问控制 (RBAC)
authorization: enabled
setParameter:
# 仅允许高强度的 SCRAM-SHA-256 认证机制
authenticationMechanisms: SCRAM-SHA-256
重启服务并验证未授权阻断:
# 1. 重启 MongoDB 服务使配置生效(补齐 2019 原稿漏掉的关键一步)
sudo systemctl restart mongod
# 2. 验证一:未带账号密码执行查询,必须当场被拒绝 (Unauthorized)
mongosh "mongodb://127.0.0.1:27017/order_service" --eval "db.orders.find()"
# 预期输出:MongoServerError[Unauthorized]: Command find requires authentication
# 3. 验证二:使用业务账号带显式 authSource 正常连接
mongosh "mongodb://[email protected]:27017/order_service?authSource=order_service&authMechanism=SCRAM-SHA-256"