MongoDB 3.0 到 3.6 版本期间发生的勒索攻击事件,本质上不是 MongoDB 内核的远程代码执行漏洞,而是运维侧把没有开启认证的实例直接暴露在了公网上。攻击者扫描默认端口 27017,发现无需密码即可登录,直接导出或删除数据,然后留下勒索信息。直到现在,仍有新上线的实例在重蹈覆辙。问题核心就两点:一是副本集环境下认证配置比单节点复杂,很多人图省事跳过;二是即便配了认证,权限划分、网络隔离、备份策略没跟上,防护形同虚设。下面直接讲配置方法和防护体系怎么落地。
副本集认证必须先做密钥文件互通副本集成员之间通过内部通讯同步 oplog,这个通道同样需要认证。MongoDB 的做法是让所有成员使用同一个密钥文件,节点之间通过它来互相验证身份。生成密钥文件用 openssl 命令,不要手工编一串字符,熵值不够。执行:
openssl rand -base64 756 > /data/mongodb/keyfile
密钥文件权限必须设置为 400,属主是 mongod 进程的运行用户,否则 mongod 会拒绝启动并提示“permissions on keyfile are too open”。把这个文件拷贝到副本集每个成员的相同路径下,注意用 scp 或 rsync 传输时保留权限。如果某个节点密钥文件内容不一致,该节点会卡在 RECOVERING 状态,日志里出现“authentication handshake failed”。
启动参数里同时开启内外部认证mongod.conf 里需要同时配置 security 段落和 replication 段落。关键配置如下:
security: authorization: enabled keyFile: /data/mongodb/keyfile replication: replSetName: rs0
authorization: enabled 控制客户端连接需要用户名密码,keyFile 控制副本集内部通讯认证。两者缺一不可。很多事故是因为只配了 keyFile 没开 authorization,外部客户端依然可以无密码访问。重启 mongod 时建议逐个节点滚动重启,先重启从节点,最后重启主节点,避免整个副本集同时不可用。
创建用户必须区分角色和最小权限连接到主节点后,先创建管理员用户。不要直接给 root 角色到处用。标准做法是创建至少三个账户:一个全局管理员用于运维,一个读写账户用于应用程序,一个只读账户用于报表或备份读取。示例:
use admin
db.createUser({
user: "siteAdmin",
pwd: "强密码",
roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "clusterAdmin"]
})
db.createUser({
user: "appUser",
pwd: "强密码",
roles: [{ role: "readWrite", db: "业务库名" }]
})
db.createUser({
user: "backupUser",
pwd: "强密码",
roles: [{ role: "read", db: "业务库名" }]
})
应用程序连接字符串里不要使用 admin 库下的高权限账户。一旦应用被 SQL 注入或代码泄露,攻击者拿到的权限越大,损失越惨重。备份账户同理,只给 read 角色,防止备份脚本被篡改后执行 dropDatabase。
连接字符串必须处理副本集拓扑和认证源客户端连接副本集时,连接字符串要指定 replicaSet 参数和 authSource。标准格式为:
mongodb://appUser:密码@host1:27017,host2:27017,host3:27017/业务库名?replicaSet=rs0&authSource=业务库名
如果用户建在 admin 库下,authSource 就填 admin。很多连接失败是因为用户建在 admin,但连接字符串里没指定 authSource,驱动默认去业务库里找用户,结果认证不通过。另外连接字符串里至少要写两个成员地址,防止主节点故障时客户端连不上副本集。
网络层隔离是防勒索的最后一道物理防线即使认证配置正确,也不应该把 MongoDB 端口直接暴露在公网上。使用云服务商的安全组或本机防火墙,只放行应用服务器和运维跳板机的 IP。iptables 示例:
iptables -A INPUT -p tcp --dport 27017 -s 应用服务器IP -j ACCEPT iptables -A INPUT -p tcp --dport 27017 -s 跳板机IP -j ACCEPT iptables -A INPUT -p tcp --dport 27017 -j DROP
云环境下,安全组规则比系统防火墙优先级更高,两者配合使用。不要把 MongoDB 绑定在 0.0.0.0 上,如果应用和数据库在同一内网,bindIp 应设置为内网 IP,而不是全部接口。
备份策略决定被勒索后能否恢复数据认证和网络隔离能防住大部分入侵,但无法杜绝内部人员误操作或高级持续性威胁。备份是最后一道防线。Mongodump 适合小规模逻辑备份,大数据量用文件系统快照或 MongoDB 原生的文件拷贝方式。备份文件必须异地存储,且备份服务器不与生产环境在同一安全域。定期做恢复演练,验证备份文件可用性。很多团队备份跑了一年,真到恢复时发现备份文件损坏,这种情况比没备份更致命。
审计日志和告警让入侵行为可追溯企业版 MongoDB 支持审计日志,社区版可以通过 mongod 的 verbose 日志配合外部日志分析工具实现基本审计。重点监控的操作为:dropDatabase、dropCollection、createUser、grantRolesToUser。一旦出现非运维窗口期的这类操作,立即触发告警。日志分析可以用 ELK 或 Loki 搭建,关键字匹配后通过企业微信或邮件通知。响应时间越短,数据被全量删除的概率越低。
版本升级与补丁管理不能滞后MongoDB 每个大版本都有安全修复,尤其是 4.0 以后对认证机制和 TLS 支持做了大量加固。还在跑 3.4 或 3.6 版本的实例,应尽快升级到 5.0 或 6.0。升级前先在测试环境验证驱动兼容性,然后按从节点、主节点的顺序滚动升级。升级过程中副本集仍然可以提供服务,只是主节点切换时会有几秒写入中断。对于无法立即升级的老版本,至少开启 TLS 传输加密,防止中间人窃听认证凭证。
权限定期审计和密码轮换每季度检查一次数据库用户列表,清理离职员工账号和不再使用的应用账号。密码轮换可以通过脚本调用 updateUser 命令实现,轮换后同步更新应用的密钥管理系统。密码复杂度要求至少 16 位,包含大小写字母、数字和特殊字符,避免使用字典单词。密钥文件本身也需要定期更换,更换流程是先生成新密钥文件,替换到所有节点,然后逐个重启 mongod,整个过程副本集不会中断服务。
总结MongoDB 副本集的勒索防护不是某个单一技术点,而是一整套配置和运维体系的组合。认证是门槛,密钥文件是副本集内部信任的基础,网络隔离和最小权限原则大幅缩小攻击面,备份和审计是兜底手段。把这几个环节都做到位,攻击者即使扫描到端口也无法登录,即使登录了也拿不到删库权限,即使删了库你也能从备份恢复。安全没有一劳永逸,持续监控和定期演练才是长期有效的策略。
