生产环境必须禁用root角色,因其隐式含__system权限可绕过库级隔离,导致跨库误删;应为业务库显式授予readwrite等最小权限,并通过disablelistdatabase参数或自定义角色彻底限制跨库操作。

生产环境禁用 root 角色是防止误删数据库的第一道铁闸——它不是“建议”,而是必须执行的底线操作。
为什么 root 角色会直接导致跨库误删
root 角色隐式包含 __system 权限,能绕过所有库级隔离机制。用户一旦认证成功,use otherdb 切库后可直接执行 db.dropDatabase(),且不会触发二次鉴权。
- 典型错误:在
admin库运行db.createUser({user:"app", pwd:"x", roles:["root"]}) - 后果:该账号连上任意库后,只要执行
use production→db.dropDatabase()就清空整个库 - 云服务(如 Atlas)虽限制部分系统命令,但
root仍可能导出其他租户数据,取决于底层隔离强度
如何为单个业务库精确授予 readWrite 权限
权限绑定必须显式指定 db 字段,MongoDB 不会根据连接串里的 authSource 或默认库自动推断作用域。
- ✅ 正确写法(在
admin库中执行):db.createUser({user:"app_user", pwd:"p", roles:[{role:"readWrite", db:"myapp"}]}) - ❌ 错误写法:
roles:["readWrite"]—— 权限实际绑定到当前认证库(通常是admin),而非目标业务库 -
readWrite不含createCollection,建新集合需额外加dbAdmin角色,且必须限定在同一个db:"myapp"
怎样彻底禁用 listDatabases 和跨库 use 行为
MongoDB 默认允许任何有角色的用户执行 listDatabases,这等于暴露全部库名;而 use otherdb 本身不校验权限,只靠后续命令报错拦截,风险极高。
- 启动时加参数:
--setParameter disableListDatabase=1(4.2+ 版本支持),否则仅靠角色无法屏蔽 - 更可靠的是自定义最小权限角色:
db.createRole({role:"appMinimal", privileges:[{resource:{db:"myapp", collection:""}, actions:["find","insert","update","remove"]}], roles:[]}) - 验证方式:
db.adminCommand({listDatabases:1})应返回"not authorized",且use logs后执行db.collection.find()必须失败
连接字符串中 authSource 和实际权限库不一致怎么办
这是最容易被忽略的配置陷阱:authSource 只指定认证凭据存储位置,和权限作用域完全无关。权限始终由 roles 中的 db 字段决定。
- 错误假设:用
mongodb://u:p@host/myapp?authSource=admin连接,就认为权限自动落在myapp上 - 真实逻辑:如果创建用户时写的是
{role:"readWrite", db:"admin"},那这个用户对myapp库零权限 - 务必检查:
db.getUser("app_user")输出中的roles数组,确认每个role对应的db值是否准确
最危险的不是没设权限,而是设了看似合理的权限却因 db 字段缺失或错配,让权限实际挂在了 admin 库上——这种配置在测试环境几乎不暴露问题,上线后一次误操作就能触发全量删除。











