dbAdmin角色隐式包含listCollections、listIndexes、collStats、dbStats等危险权限,无法拆解,必须用自定义角色精确授权业务集合,禁用system.*访问。

普通用户默认不能访问 system.* 集合,但一旦被授予 dbAdmin 角色(哪怕只在某个数据库上),就会自动获得 listCollections、listIndexes 等元数据操作权限——这会导致他们能 show collections、甚至看到 system.users、system.roles 这类敏感集合。真想禁止查看,不能靠“不给 dbAdmin”,而得主动剥离或绕过它。
dbAdmin 角色自带哪些危险权限?
dbAdmin 不是只管“管理数据库”,它隐式包含一堆元数据读取动作,比如:
-
listCollections:直接让show collections返回所有集合,包括system.* -
listIndexes:可查任意集合的索引结构,暴露字段设计 -
collStats、dbStats:泄露数据量、存储大小等运营信息 - 最关键的是:
dbAdmin无法拆解——你不能删掉其中某几项,它是个原子角色
替代方案:用自定义角色精确控制 listCollections
与其授 dbAdmin 再想办法拦,不如彻底不用。真正可控的方式是自己建角色,只给明确需要的集合和动作:
- 不要写
{ role: "dbAdmin", db: "myapp" },改用db.createRole() - resource 中显式列出业务集合,例如
{ db: "myapp", collection: "orders" },**不写collection: ""或留空** - 如果必须让普通用户能
show collections,只加一条独立 privilege:{ resource: { db: "myapp", collection: "" }, actions: ["listCollections"] }—— 注意这里collection: ""才表示“数据库级列表”,不是通配符 - 绝对不要给
system.*单独授权;MongoDB 不允许在resource中写collection: "system.users",写了也无效
验证时容易忽略的两个硬限制
权限生效后,仍可能看到系统集合,原因往往不是配置错,而是:
- 连接时没指定
--authenticationDatabase admin,导致认证走错库,权限根本没加载 - 客户端(如 Compass 或某些 ORM)启动时自动执行
db.runCommand({listCollections: 1}),而你的角色没显式拒绝该命令——MongoDB 没有“deny”机制,**没授权 = 拒绝**,但前提是命令真被拦截了;如果用户有其他角色叠加出对应权限,就会绕过 - 更隐蔽的是:
dbAdmin权限会缓存在连接池里,换用户登录后,得断开重连,不能只db.auth()切换
最稳妥的做法,是完全避开 dbAdmin,从第一行 db.createRole() 就只声明业务集合 + 明确动作。系统集合不是“需要隐藏的东西”,而是“本就不该出现在普通用户视野里的东西”——MongoDB 的权限模型里,它们天然不可见,除非你亲手把钥匙递过去。











