MongoDB默认配置下最容易出问题的环节不是复杂的注入攻击,而是裸奔式的网络暴露和过度宽松的账号权限。很多团队把27017端口直接绑定在公网地址上,或者虽然绑定了内网但整个内网网段都能无密码访问,这在勒索事件中已经被反复验证是灾难性的。优化安全管控的第一步不是上什么高级审计工具,而是把网络监听地址从0.0.0.0改成具体的内网IP,同时确认防火墙规则只放行应用服务器到数据库端口的访问路径。
在配置文件mongod.conf中,bindIp字段经常被误解。它并不是一个简单的“允许谁连”的开关,而是控制MongoDB进程监听在哪些本地网卡上。生产环境建议明确写为应用所在网段的内部IP,而不是逗号分隔一堆地址。如果应用和数据库同机部署,直接写127.0.0.1最稳妥。改完后务必检查net.port是否还是默认27017,虽然改端口不是真正的安全措施,但能降低自动化扫描工具命中概率。
net: port: 27017 bindIp: 10.10.20.5 ipv6: false
账号体系方面,MongoDB的认证机制经历了从MONGODB-CR到SCRAM-SHA-1再到SCRAM-SHA-256的演进。现在新建实例默认使用SCRAM-SHA-256,但如果是从老版本升级上来的,很可能还在用SCRAM-SHA-1。两种机制的安全性差距明显,SCRAM-SHA-256在密码哈希和挑战应答过程中提供了更强的抗暴力破解能力。升级认证机制不能直接改配置,需要重新创建用户并指定mechanisms参数。
db.createUser({
user: "app_user",
pwd: "strong_password_here",
roles: [
{ role: "readWrite", db: "business_db" }
],
mechanisms: ["SCRAM-SHA-256"]
})
权限分配上最常见的错误是把root角色或者dbOwner角色直接给应用账号。root角色拥有实例级别的全部权限,包括管理数据库、复制集和分片配置;dbOwner虽然限定在单个库,但依然包含索引管理、集合删除等破坏性操作。应用账号只需要readWrite或者更细粒度的read角色。如果应用只做查询,就只给read。如果应用只操作某几个集合,MongoDB支持在角色中限定集合范围,这一点很多团队没有利用起来。
db.createRole({
role: "order_query_role",
privileges: [
{
resource: { db: "business_db", collection: "orders" },
actions: ["find"]
},
{
resource: { db: "business_db", collection: "order_logs" },
actions: ["find", "insert"]
}
],
roles: []
})
连接字符串的安全参数同样值得逐项检查。很多应用在连接MongoDB时只写了用户名密码,没有指定authSource,这会导致认证请求发送到错误的库上,触发认证失败或者意外回退。authSource应该明确指向创建用户时所在的数据库,通常是admin或者应用库本身。另外,连接字符串中的readPreference和writeConcern虽然不直接影响安全,但错误的配置可能导致应用在故障切换时连接到非预期节点,间接增加数据暴露面。
mongodb://app_user:strong_password@10.10.20.5:27017/business_db?authSource=admin&replicaSet=rs0&readPreference=secondaryPreferred
审计日志是安全管控中经常被忽略但极其重要的一环。MongoDB企业版自带审计功能,社区版则需要通过第三方工具或者操作系统层面的日志来补足。审计日志要记录的不只是登录失败事件,还包括权限变更、用户创建删除、角色修改等管理操作。很多安全事件中,攻击者进入系统后的第一步就是创建新的高权限账号,如果审计日志没有开启或者没有覆盖这些操作,事后排查会非常困难。企业版中可以通过auditLog.destination配置为文件或者syslog,并设置filter来控制记录范围,避免日志爆炸。
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/audit.log
filter: '{ atype: { $in: ["authenticate", "createUser", "dropUser", "updateUser", "grantRolesToUser", "revokeRolesFromUser"] } }'
网络层之外,MongoDB的TLS加密配置在生产环境中执行率并不高,原因是配置证书和客户端兼容性测试比较繁琐。但数据在网络上明文传输意味着任何能抓包的内网机器都能看到查询内容和返回结果。对于跨机房或者跨地域部署的场景,TLS是必须的。配置时要注意net.tls.mode的值,preferTLS模式允许非TLS连接回退,这在安全上等于没有强制。生产环境应该设置为requireTLS,并且同时配置CA文件和证书文件。客户端连接字符串需要加上tls=true参数,如果使用自签名证书,还需要指定tlsAllowInvalidCertificates或者正确配置CA。
net:
tls:
mode: requireTLS
certificateKeyFile: /etc/mongodb/ssl/mongodb.pem
CAFile: /etc/mongodb/ssl/ca.pem
另一个容易被忽视的细节是MongoDB的HTTP状态接口和REST API。老版本MongoDB默认开启HTTP接口,虽然功能有限,但会暴露实例状态信息,包括连接数、操作统计等。新版本已经默认关闭,但如果是老版本升级上来的,需要确认net.http.enabled和net.http.RESTInterfaceEnabled是否已经显式设置为false。这些接口在现代版本中已经废弃,留着没有任何业务价值,只会增加攻击面。
副本集和分片集群的安全配置比单机复杂得多。副本集成员之间的内部认证需要配置keyfile或者x.509证书。keyfile方式简单但安全性一般,本质上是一个共享密钥文件,所有成员使用同一个文件内容进行内部认证。x.509证书方式更安全,但配置复杂度高。无论选择哪种方式,内部认证都必须开启,否则攻击者可以伪装成副本集成员加入集群,直接读取数据或者篡改复制流。keyfile的权限必须是400或者600,文件内容要足够随机,不能使用简单字符串。
security: keyFile: /etc/mongodb/keyfile authorization: enabled
备份数据的安全管控同样不能放松。mongodump导出的数据默认是明文BSON格式,任何人拿到备份文件都能直接读取。生产环境的备份文件需要加密存储,并且备份文件的访问权限要独立于数据库账号体系。很多团队把备份文件和数据库放在同一台服务器上,数据库被攻破后备份也被一锅端。正确的做法是备份完成后立即传输到独立的备份存储中,并且使用加密工具或者存储层的加密能力保护备份文件。恢复备份时也要验证备份文件的完整性,防止备份文件被篡改后植入恶意数据。
版本更新和补丁管理是安全管控中成本最低但效果最直接的手段。MongoDB官方会定期发布安全公告,修复已知的权限绕过、拒绝服务等问题。很多生产环境还在运行已经停止支持的旧版本,这些版本存在的已知漏洞在公开渠道可以查到详细的利用方式。升级版本需要做兼容性测试,但安全补丁版本通常不需要修改应用代码。建议至少保持在大版本的最新补丁版本上,例如4.4系列的最新补丁,而不是停留在4.4.0这样的初始版本。
监控和告警方面,安全相关的指标需要单独建立告警规则。例如连续登录失败次数、来自非白名单IP的连接尝试、权限变更操作、异常时段的数据库活动等。这些告警不能只依赖MongoDB自身的日志,还需要结合操作系统层面的监控。例如通过分析mongod日志中的认证失败记录,配合防火墙日志中的来源IP,可以快速定位暴力破解行为。告警阈值要设置得合理,太敏感会导致告警疲劳,太宽松则会漏掉真实攻击。
最后要强调的是安全配置的定期复核。MongoDB的权限体系是动态变化的,开发人员可能临时申请了高权限账号用于调试,事后忘记回收;新上线的应用可能被分配了过宽的权限;离职人员的账号可能没有及时删除。这些情况都需要通过定期审计来发现。可以编写脚本定期导出用户列表和角色绑定关系,与预期的权限基线进行对比,发现差异后及时处理。安全管控不是一次性配置完就结束的事情,而是一个持续运行的过程。
