MongoDB的默认配置从来不是为了直接投入生产环境而设计的。很多团队在完成安装后,使用默认的空口令或弱口令,直接将服务暴露在公网或内网中,这等于把数据库的大门敞开。最直接的后果就是遭遇勒索攻击,数据被清空,只留下一个要求支付赎金的库。解决这个问题不需要复杂的架构调整,从安装完成后的第一步就应该执行安全加固。

强制启用身份认证并创建管理员账户

MongoDB默认不开启认证,这意味着任何能连接到27017端口的人都可以对数据库执行任意操作。安全配置的第一步是修改配置文件,启用身份验证。找到mongod.conf文件,在security部分增加如下配置:

security:
  authorization: enabled

重启服务后,数据库会要求所有连接提供凭证。此时还没有任何用户,需要先创建一个拥有root角色的超级管理员。连接数据库后,切换到admin库执行:

use admin
db.createUser({
  user: "adminUser",
  pwd: "yourStrongPassword",
  roles: [ { role: "root", db: "admin" } ]
})

这个账户仅用于管理操作,日常业务绝不能使用root角色。紧接着为每个业务数据库创建专用账户,遵循最小权限原则。比如某个应用只需要读写app_db库,就只授予readWrite角色,绝不赋予dbAdmin或userAdmin这类管理权限。

基于角色的访问控制细化权限

很多运维人员习惯直接给应用账户分配dbOwner角色,这会导致该账户可以删除集合、创建索引甚至删除数据库。正确的做法是梳理应用的实际需求。如果应用只需要读写某个集合,可以创建自定义角色:

db.createRole({
  role: "inventoryRW",
  privileges: [
    { resource: { db: "app_db", collection: "inventory" }, actions: ["find", "insert", "update", "remove"] }
  ],
  roles: []
})

然后将这个自定义角色赋予应用账户。这样做的好处是,即使应用层出现SQL注入或代码漏洞,攻击者通过这个数据库账户也无法执行删除集合或清空数据的危险操作。对于数据分析团队,只分配read角色并限制在特定集合上。定期审计每个账户的权限,回收不再使用的账户,是防止权限蔓延的关键。

网络层隔离与绑定IP限制

MongoDB默认绑定所有网络接口,这在云服务器上尤其危险。修改配置文件中的bindIp参数,将其设置为应用服务器的内网IP地址或127.0.0.1。如果应用和数据库在同一台机器上,直接绑定本地回环地址:

net:
  port: 27017
  bindIp: 127.0.0.1

对于分布式部署,将bindIp设置为内网网卡的IP地址,确保数据库端口不暴露在公网上。同时利用云服务商的安全组或本机防火墙,只放行应用服务器到数据库端口的入站流量。例如使用iptables限制来源IP:

iptables -A INPUT -s 10.0.1.100 -p tcp --dport 27017 -j ACCEPT
iptables -A INPUT -p tcp --dport 27017 -j DROP

这样做即使认证凭证意外泄露,攻击者也无法从外部网络直接连接到数据库。对于跨机房或跨地域的复制集通信,使用VPN或专线建立加密通道,而不是将MongoDB端口直接暴露在公网上。

传输层加密TLS/SSL配置

内网通信同样需要加密。很多安全事件表明,内网流量被嗅探的风险真实存在。启用TLS加密客户端与服务器之间、以及复制集成员之间的通信。首先生成证书,然后修改配置文件:

net:
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/ssl/mongodb.pem
    CAFile: /etc/ssl/ca.pem

复制集成员之间的内部认证也需要单独配置。使用密钥文件或X.509证书来验证成员身份,防止恶意节点加入复制集。生成一个长随机字符串作为密钥文件,并将其部署到所有复制集节点:

security:
  keyFile: /etc/ssl/mongodb-keyfile

密钥文件的权限必须设置为400,仅mongod进程可读。如果密钥文件权限过于宽松,MongoDB会拒绝启动。这是数据库层面的强制检查,目的是防止其他系统用户读取到密钥内容。

审计日志开启与异常行为监控

当所有预防措施都部署到位后,还需要记录谁在什么时间做了什么操作。MongoDB企业版提供完整的审计功能,社区版则可以通过配置日志级别来记录关键操作。在配置文件中设置审计日志输出:

auditLog:
  destination: file
  format: JSON
  path: /var/log/mongodb/auditLog.json

对于社区版,至少应该记录身份验证事件和关键命令执行情况。通过设置日志组件的详细级别,可以捕获dropDatabase、deleteMany等危险操作。将这些日志接入集中式日志平台,设置告警规则。例如,当检测到短时间内大量删除操作或来自陌生IP的连接尝试时,立即触发告警。

禁用不安全的服务端功能

MongoDB提供了一些便于开发调试但生产环境极其危险的功能。Server-side JavaScript允许在数据库服务器上执行JavaScript代码,这为注入攻击打开了大门。在配置文件中禁用它:

security:
  javascriptEnabled: false

REST API接口默认开启,但没有任何认证机制,必须在生产环境中关闭。同样,HTTP状态页面也会泄露数据库的运行信息,应该一并禁用。这些功能在较新版本的MongoDB中已经默认关闭,但对于使用旧版本的系统,务必检查并手动关闭。

数据加密与备份策略

即使攻击者获取了物理存储介质,也不应该能读取到数据。MongoDB企业版支持存储引擎加密,社区版则可以在文件系统层使用LUKS或云服务商提供的加密磁盘。配置WiredTiger存储引擎的加密选项,需要提供一个密钥文件:

security:
  enableEncryption: true
  encryptionKeyFile: /etc/ssl/encryption.key

备份数据同样需要加密。使用mongodump导出数据时,配合文件系统加密或压缩工具对备份文件进行加密处理。定期验证备份的可用性和完整性,因为勒索攻击往往会在潜伏期感染备份文件。将备份存储在与生产环境隔离的对象存储中,并设置不可变策略,防止备份数据被删除或篡改。

版本更新与漏洞管理

MongoDB的每个大版本都会修复已知的安全漏洞。运行过时的版本是很多安全事件的根本原因。建立定期的版本评估和升级流程,关注MongoDB官方发布的安全公告。升级前在测试环境验证兼容性,尤其是驱动程序版本与数据库版本的匹配。对于无法立即升级的系统,通过配置参数临时缓解已知漏洞的利用条件,但必须制定明确的升级时间表。

连接字符串安全与凭证管理

应用代码中硬编码数据库连接字符串是常见的安全隐患。使用环境变量或密钥管理服务来存储凭证。连接字符串中不应包含明文密码,而应引用外部配置。对于容器化部署,通过Kubernetes Secrets或Docker Secrets注入凭证。同时,连接字符串中应指定认证数据库、TLS参数和读取偏好,避免应用在运行时进行不安全的连接回退:

mongodb://username@hostname:27017/dbname?authSource=admin&tls=true

密码定期轮换,并确保轮换过程中应用可以无缝切换。MongoDB支持SCRAM认证机制,密码在传输过程中经过加盐哈希处理,但密码本身的强度仍然至关重要。强制使用长度超过16位、包含大小写字母、数字和特殊字符的密码。

安全配置不是一次性的工作。每次业务变更、架构调整或版本升级后,都需要重新评估数据库的安全态势。将上述配置项纳入自动化部署脚本或配置管理工具中,确保每个新创建的MongoDB实例都符合安全基线。定期进行渗透测试和安全审计,从攻击者的视角验证防御措施的有效性,才能持续保持数据库的安全状态。