自定义角色必须显式排除drop等高危操作,新建角色仅声明必要权限;修改现有角色需先revoke再grant;角色须在业务库创建并限定具体资源;授权后须用对应库认证并实测验证。

自定义角色时显式排除 drop 和 dropDatabase 操作
内置角色如 readWrite 或 dbOwner 默认包含 drop,不能直接禁用。必须新建角色,只声明业务真正需要的操作,不写进 drop、dropDatabase、collMod(含 dropCollection)等高危动作。
常见错误是照搬 readWrite 权限列表却漏删 drop;或误以为“没写就是默认禁止”——实际上权限是白名单制,但内置角色已预设了这些操作,必须主动剔除。
示例:只允许对 orders 集合做查询和插入:
db.createRole({
role: "orderWriter",
privileges: [
{ resource: { db: "appDB", collection: "orders" }, actions: ["find", "insert"] }
],
roles: []
})
db.grantPrivilegesToRole() 不会覆盖已有特权,要先 db.revokePrivilegesFromRole()
如果角色已存在且绑定了含 drop 的权限,后续调用 db.grantPrivilegesToRole() 只会追加,不会替换或删除旧权限。
必须显式回收:
- 查当前权限:
db.getRole("orderWriter", { showPrivileges: true }) - 确认哪些 privilege 包含
drop后,用db.revokePrivilegesFromRole()移除对应条目 - 再补上干净的
find/insert等
遗漏这一步,grant 操作看似成功,实际 drop 权限仍在生效。
避免在 admin 数据库上创建泛作用域角色
在 admin 库创建角色时,若 resource 设为 { db: "", collection: "" } 或 { anyResource: true },该角色可能隐式获得跨库 dropDatabase 权限(尤其当继承 dbAdminAnyDatabase 类角色时)。
安全做法:
- 角色始终在业务数据库(如
appDB)中创建,而非admin -
resource明确限定到具体db和collection,不使用空字符串或通配符 - 绝不让自定义角色继承
dbAdmin、dbAdminAnyDatabase等内置管理角色
验证权限是否真被限制住
授权完成后,必须用目标用户连接并实测,不能只看角色定义。容易忽略的关键点:
- 连接时认证的数据库必须与角色所在库一致(如角色在
appDB创建,就得use appDB再db.auth()) - 执行
db.orders.drop()前,先试db.runCommand({ listCollections: 1 })确认能访问集合——否则报错可能是“无集合访问权”,而非“无 drop 权” - 错误信息里出现
"not authorized on appDB to execute command { drop: \"orders\" }"才算生效;若报"ns does not exist"或超时,说明根本没走到权限校验环节
权限收敛不是一劳永逸的事,每次更新角色后都得重走一遍验证路径,尤其涉及 Ops Manager 同步场景下,Synced: Yes 的角色修改可能延迟生效或被覆盖。











