2. MongoDB安全架构与威胁模型

MongoDB 的安全能力不是单一开关,而是一组按“先证明身份、再决定能做什么、再保护数据本身、最后留下可追溯证据”顺序协同工作的机制。理解这条链路,才能判断一次配置到底补上了哪一层,以及攻击者可能从哪一层绕过。

四层安全机制的分工

认证(Authentication)解决“你是谁”。MongoDB 支持 SCRAM-SHA-256(默认,用户名口令挑战应答)、x.509 证书、LDAP 代理认证和 Kerberos。副本集与分片集群必须启用内部认证(keyfile 或 x.509),否则节点间通信可被伪造。

授权(Authorization)解决“你能做什么”。基于角色的访问控制(RBAC)把权限绑定到角色,再把角色授予用户。权限由“资源 + 动作”组成,例如 { resource: { db: "shop", collection: "orders" }, actions: ["find","insert"] }。内置角色如 read、readWrite、dbAdmin、clusterMonitor、root 覆盖常见场景,最小权限原则要求优先使用自定义角色而非直接给 root。

加密(Encryption)分三个层面:传输加密(TLS/SSL,保护客户端与节点、节点与节点之间的链路)、静态加密(WiredTiger 加密存储引擎,保护磁盘文件与备份)、字段级加密(CSFLE / Queryable Encryption,保护敏感字段,使数据库管理员也看不到明文)。三者保护的对象不同,不能互相替代。

审计(Audit)解决“发生过什么”。MongoDB Enterprise 的审计功能可把认证、授权失败、DDL、CRUD 等事件写入 JSON 文件或 syslog,是合规取证与异常检测的基础。社区版可用 db.currentOp()、慢查询日志、profiler 与外部日志采集部分替代。

MongoDB 安全链路与攻击面对应关系 客户端 / 应用 连接串 + 凭据 ① 认证 SCRAM / x.509 / LDAP 副本集内部 keyfile 攻击面:弱口令、未启用认证 ② 授权 RBAC 角色 → 资源 + 动作 最小权限 / 自定义角色 攻击面:过度授权、root 滥用 ③ 加密 TLS / 静态 / 字段级 密钥管理 KMS 攻击面:明文传输、密钥泄露 ④ 数据存储层:WiredTiger 加密存储引擎 + 集合级访问控制 保护对象:数据文件、索引、备份快照、oplog ⑤ 审计:认证事件 / 授权失败 / DDL / CRUD → JSON 或 syslog 用途:合规取证、异常检测、责任追溯 攻击面:审计关闭、日志被篡改或删除 威胁建模 STRIDE / 攻击树 数据流图 + 信任边界 常见攻击面速查 ● 未启用认证 / 绑定 0.0.0.0 ● 弱口令与凭据硬编码 ● 过度授权 / root 直连 ● 未启用 TLS 明文传输 ● 注入类 NoSQL 操作符攻击 ● 备份与 oplog 未加密

常见攻击面与真实威胁场景

MongoDB 历史上最典型的事故是“未启用认证 + 监听公网”。默认配置下若 bindIp 为 0.0.0.0 且未开启 security.authorization,任何能连到 27017 端口的人都可以直接读写全部数据库。攻击者常用脚本批量扫描 27017 端口,连接后执行 db.getCollectionNames() 枚举集合,再 dropDatabase() 并留下勒索信息。

第二类攻击面是注入。MongoDB 查询本身是文档,但应用若把用户输入直接拼进查询对象,攻击者可传入 {"$ne": null} 或 {"$gt": ""} 绕过条件判断。例如登录查询 db.users.find({user: username, pwd: password}),若 password 被替换为 {"$ne": 1},则条件恒真。防御手段是类型校验、使用 express-mongo-sanitize 类中间件剥离 $ 与 . 开头的键,以及禁用服务端 JavaScript(--noscripting)。

第三类是权限提升与横向移动。若应用账号拥有 dbAdmin 或 userAdminAnyDatabase,一旦被攻破,攻击者可创建新管理员账号、修改其他用户口令,甚至通过 db.runCommand({createUser:...}) 持久化后门。因此应用账号应严格限制在业务库的读写权限,管理操作走独立账号并配合 IP 白名单。

威胁建模方法:从数据流图到 STRIDE

威胁建模的目标是在编码前识别“哪里可能被攻破”。推荐流程:先画数据流图(DFD),标出外部实体、进程、数据存储与数据流;再划出信任边界(如公网→负载均衡、应用→数据库、数据库→备份存储);然后对每条跨越信任边界的数据流套用 STRIDE 六类威胁:仿冒(Spoofing)、篡改(Tampering)、抵赖(Repudiation)、信息泄露(Information Disclosure)、拒绝服务(Denial of Service)、权限提升(Elevation of Privilege)。

以“应用服务器 → MongoDB 副本集”这条流为例:仿冒对应未启用认证或弱口令;篡改对应未启用 TLS 导致中间人改写;信息泄露对应未启用字段级加密导致备份泄露;抵赖对应审计未开启;拒绝服务对应未限制连接数与查询复杂度;权限提升对应应用账号拥有 root。每条威胁再给出缓解措施与验证方式,形成可跟踪的清单。

威胁建模不是一次性文档。每次新增集合、新增外部集成或调整网络拓扑时,都应重新审视信任边界与对应威胁,否则模型会迅速过期。

最小可用的安全配置示例

下面是一份启用认证、TLS 与审计的 mongod.conf 片段,参数为教学示例,实际部署需替换为真实证书路径与密钥文件:

net:
  port: 27017
  bindIp: 10.0.1.21,127.0.0.1
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/ssl/mongodb.pem
    CAFile: /etc/ssl/ca.pem

security:
  authorization: enabled
  keyFile: /etc/mongo/keyfile
  javascriptEnabled: false

auditLog:
  destination: file
  format: JSON
  path: /var/log/mongodb/audit.json
  filter: '{ atype: { $in: ["authenticate","authCheck","createUser","dropDatabase"] } }'

setParameter:
  authenticationMechanisms: SCRAM-SHA-256

验证时先确认未认证连接被拒绝:mongosh --host 10.0.1.21 --port 27017 应报认证错误;再用只读账号执行 db.orders.insertOne({}),应返回 Unauthorized;最后检查 audit.json 中是否出现对应的 authCheck 失败记录。三步都通过,说明认证、授权、审计三层已生效。

启用 authorization 前必须先创建管理员用户,否则将无法执行任何需要授权的操作。建议在本地回环地址上先建好 userAdminAnyDatabase 账号,再开启授权并重启。

加密的落地要点

TLS 要同时覆盖客户端连接与副本集内部通信,否则节点间复制仍是明文。静态加密需在启动时通过 --encryptionKeyFile 或 KMIP 提供主密钥,密钥一旦丢失数据不可恢复,因此密钥必须独立于数据库备份存放。字段级加密适合身份证号、手机号、支付信息等字段,客户端加密后再写入,服务端只存密文;其代价是无法对加密字段做范围查询(Queryable Encryption 可部分支持等值查询),需要在安全与查询能力之间权衡。

把四层机制串起来看:认证挡住匿名访问,授权限制已认证用户的动作范围,加密保护数据在传输、磁盘与字段三个位置的机密性,审计为前两者提供可验证的记录。威胁建模则是在部署前主动找出这四层各自的薄弱点,并用可执行的配置与验证步骤逐一封堵。