MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MongoDB副本集安全性配置与增强

2023-10-153.1k 阅读

MongoDB 副本集安全性基础配置

启用身份验证

在 MongoDB 副本集中,启用身份验证是保障安全性的基础步骤。这能确保只有经过授权的用户才能访问数据库。

  1. 创建管理员用户
    • 首先连接到 MongoDB 副本集的主节点。可以使用 mongo 命令行工具:
mongo --host primary_host:port
  • 切换到 admin 数据库,因为管理员用户通常创建在这个数据库中:
use admin
  • 创建管理员用户,例如:
db.createUser({
    user: "adminUser",
    pwd: "adminPassword",
    roles: [ { role: "root", db: "admin" } ]
})

这里 root 角色赋予了用户在整个 MongoDB 实例上的最高权限。

  1. 启用身份验证
    • 修改 MongoDB 配置文件(通常在 /etc/mongod.conf 或其他指定路径),添加或修改以下配置:
security:
  authorization: enabled
  • 保存配置文件后,重启 MongoDB 服务,使配置生效。在大多数 Linux 系统上,可以使用以下命令:
sudo systemctl restart mongod

之后,当连接到 MongoDB 时,就需要提供用户名和密码。例如:

mongo --host primary_host:port -u "adminUser" -p "adminPassword" --authenticationDatabase "admin"

配置密钥文件

密钥文件用于副本集成员之间的身份验证,确保只有授权的节点可以加入副本集。

  1. 生成密钥文件
    • 使用 openssl 工具生成一个随机的密钥文件,例如:
openssl rand -base64 756 > /path/to/mongodb.key
  • 设置密钥文件的权限,只有 MongoDB 进程能读取它:
chmod 400 /path/to/mongodb.key
  1. 配置副本集使用密钥文件
    • 修改每个副本集成员的 MongoDB 配置文件,添加以下内容:
security:
  keyFile: /path/to/mongodb.key
  • 重启每个副本集成员的 MongoDB 服务,使配置生效。这样,副本集成员之间就通过密钥文件进行身份验证,增强了副本集内部通信的安全性。

网络安全配置

绑定 IP 地址

  1. 限制监听地址
    • MongoDB 默认监听所有网络接口(0.0.0.0),这在生产环境中存在安全风险。建议将其绑定到特定的 IP 地址,比如服务器的内部 IP 地址或仅允许访问的外部 IP 地址。
    • 修改 MongoDB 配置文件,找到 net 部分,修改 bindIp 选项。例如,只绑定到内部 IP 192.168.1.100
net:
  bindIp: 192.168.1.100
  • 保存配置文件并重启 MongoDB 服务,这样 MongoDB 就只会监听指定的 IP 地址,减少了暴露在不必要网络接口上的风险。
  1. 使用防火墙
    • 结合服务器的防火墙(如 iptables 或 firewalld)进一步限制对 MongoDB 端口(默认 27017)的访问。
    • 以 iptables 为例,允许特定 IP 地址(如 192.168.1.200)访问 MongoDB 端口:
iptables -A INPUT -p tcp -s 192.168.1.200 --dport 27017 -j ACCEPT
iptables -A INPUT -p tcp --dport 27017 -j DROP

第一条规则允许指定 IP 访问,第二条规则阻止其他所有 IP 访问 MongoDB 端口。对于 firewalld,可以使用类似的命令:

firewall -cmd --zone=public --add -rich -rule='rule family="ipv4" source address="192.168.1.200" port protocol="tcp" port="27017" accept'
firewall -cmd --zone=public --add -rich -rule='rule family="ipv4" port protocol="tcp" port="27017" drop'

启用 TLS/SSL 加密

  1. 生成证书
    • 可以使用 OpenSSL 生成自签名证书,这适用于测试和开发环境。对于生产环境,建议使用受信任的证书颁发机构(CA)颁发的证书。
    • 生成私钥:
openssl genrsa -out mongodb.key 2048
  • 生成证书签名请求(CSR):
openssl req -new -key mongodb.key -out mongodb.csr -subj "/C=US/ST=California/L=San Francisco/O=Your Company Name/CN=your_domain.com"
  • 自签名证书:
openssl x509 -req -in mongodb.csr -days 365 -signkey mongodb.key -out mongodb.crt
  1. 配置 MongoDB 使用 TLS/SSL
    • 修改 MongoDB 配置文件,添加以下内容:
net:
  ssl:
    mode: requireSSL
    PEMKeyFile: /path/to/mongodb.pem
    CAFile: /path/to/ca.crt

这里 mongodb.pem 文件包含私钥和证书(可以将 mongodb.keymongodb.crt 合并到一个文件中),ca.crt 是证书颁发机构的证书(如果使用自签名证书,就是 mongodb.crt)。

  • 重启 MongoDB 服务,使配置生效。连接到 MongoDB 时,也需要指定 SSL 选项。例如:
mongo --host primary_host:port -u "adminUser" -p "adminPassword" --authenticationDatabase "admin" --ssl --sslCAFile /path/to/ca.crt

权限管理与安全策略

细粒度权限控制

  1. 创建普通用户并分配权限
    • 除了管理员用户,应该为不同的业务需求创建具有细粒度权限的普通用户。例如,为一个应用程序创建用户,该用户只能读写特定数据库中的集合。
    • 切换到目标数据库,例如 myappdb
use myappdb
  • 创建用户并分配权限,比如只允许读取 users 集合和写入 logs 集合:
db.createUser({
    user: "myappUser",
    pwd: "myappPassword",
    roles: [
        { role: "read", db: "myappdb", collection: "users" },
        { role: "write", db: "myappdb", collection: "logs" }
    ]
})
  1. 使用角色组合
    • MongoDB 提供了一些内置角色,也可以创建自定义角色并将其组合使用。例如,创建一个自定义角色 myapp_custom_role 并分配给用户:
    • 首先在 admin 数据库中创建自定义角色:
use admin
db.createRole({
    role: "myapp_custom_role",
    privileges: [
        { resource: { db: "myappdb", collection: "products" }, actions: ["find", "update"] },
        { resource: { db: "myappdb", collection: "orders" }, actions: ["insert", "delete"] }
    ],
    roles: []
})
  • 然后在 myappdb 数据库中创建用户并分配这个自定义角色:
use myappdb
db.createUser({
    user: "myappUser2",
    pwd: "myappPassword2",
    roles: [ { role: "myapp_custom_role", db: "myappdb" } ]
})

审计配置

  1. 启用审计日志
    • 审计日志可以记录 MongoDB 服务器上的各种操作,有助于安全分析和合规性检查。
    • 修改 MongoDB 配置文件,添加以下内容:
auditLog:
  destination: file
  path: /var/log/mongodb/audit.log
  format: JSON
  filter: {
      atype: { $in: ["command", "connection", "authentication"] }
  }

这里将审计日志输出到文件 /var/log/mongodb/audit.log,采用 JSON 格式,并只记录命令、连接和身份验证相关的操作。

  • 重启 MongoDB 服务,开始记录审计日志。可以使用工具如 jq 来分析 JSON 格式的审计日志。例如,查看所有身份验证相关的记录:
cat /var/log/mongodb/audit.log | jq '.[] | select(.atype == "authentication")'

防范常见安全威胁

防止注入攻击

  1. 使用参数化查询
    • 在应用程序中与 MongoDB 交互时,应避免直接拼接查询字符串,而是使用参数化查询。以 Python 的 pymongo 库为例:
from pymongo import MongoClient

client = MongoClient("mongodb://adminUser:adminPassword@primary_host:port/admin")
db = client["myappdb"]
users_collection = db["users"]

username = "testUser"
password = "testPassword"

# 错误方式,易受注入攻击
# query = "{'username': '" + username + "', 'password': '" + password + "'}"
# result = users_collection.find_one(eval(query))

# 正确方式,参数化查询
query = {'username': username, 'password': password}
result = users_collection.find_one(query)
  1. 验证和清理输入
    • 在将用户输入传递给 MongoDB 查询之前,对其进行验证和清理。例如,使用正则表达式验证用户名是否符合规范:
import re

username = "testUser"
if not re.match("^[a-zA-Z0-9_]{3,20}$", username):
    raise ValueError("Invalid username")

防范暴力破解攻击

  1. 设置合理的密码策略
    • 要求用户设置强密码,包含大小写字母、数字和特殊字符,并且有一定的长度限制。例如,在创建用户时提示用户设置强密码:
db.createUser({
    user: "newUser",
    pwd: prompt("Enter a strong password"),
    roles: [ { role: "readWrite", db: "myappdb" } ]
})
  1. 限制登录尝试次数
    • 虽然 MongoDB 本身没有内置的登录尝试次数限制功能,但可以在应用层实现。例如,使用一个计数器记录用户登录尝试次数,超过一定次数后锁定用户一段时间:
login_attempts = {}

def login(username, password):
    if username not in login_attempts:
        login_attempts[username] = 1
    else:
        login_attempts[username] += 1

    if login_attempts[username] > 5:
        print("Account locked for 10 minutes due to too many failed attempts.")
        return

    # 实际的登录验证逻辑
    client = MongoClient("mongodb://adminUser:adminPassword@primary_host:port/admin")
    db = client["myappdb"]
    users_collection = db["users"]
    user = users_collection.find_one({'username': username, 'password': password})
    if user:
        print("Login successful.")
    else:
        print("Login failed.")


监控与安全更新

监控副本集状态

  1. 使用 MongoDB 内置监控工具
    • MongoDB 提供了 rs.status() 命令来查看副本集的状态。连接到副本集的主节点后,运行该命令:
rs.status()

该命令会返回副本集的详细状态信息,包括成员状态、选举状态、同步状态等。例如,检查某个成员的状态:

var status = rs.status();
for (var i = 0; i < status.members.length; i++) {
    printjson(status.members[i]);
}
  1. 使用外部监控工具
    • 可以使用第三方工具如 Prometheus 和 Grafana 来监控 MongoDB 副本集。首先,安装并配置 MongoDB Exporter,它可以将 MongoDB 的指标暴露给 Prometheus。
    • 下载 MongoDB Exporter 二进制文件,例如:
wget https://github.com/percona/mongodb_exporter/releases/download/v0.20.3/mongodb_exporter-0.20.3.linux-amd64.tar.gz
tar -xvf mongodb_exporter-0.20.3.linux-amd64.tar.gz
cd mongodb_exporter-0.20.3.linux-amd64
  • 配置 MongoDB Exporter 连接到副本集,例如:
./mongodb_exporter --mongodb.uri="mongodb://adminUser:adminPassword@primary_host:port/admin"
  • 然后在 Prometheus 配置文件中添加 MongoDB Exporter 的地址,在 Grafana 中导入 MongoDB 相关的仪表盘模板,就可以直观地监控副本集的各种指标,如 CPU 使用率、内存使用情况、复制延迟等。

安全更新与漏洞管理

  1. 定期更新 MongoDB
    • 关注 MongoDB 官方发布的安全更新和新版本。可以在 MongoDB 官方网站的下载页面查看最新版本。
    • 在更新之前,先在测试环境中进行全面测试,确保更新不会影响业务功能。例如,在测试环境中停止 MongoDB 服务,下载并解压新版本:
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-5.0.10.tgz
tar -xvf mongodb-linux-x86_64-ubuntu2004-5.0.10.tgz
  • 备份数据,然后将新版本的二进制文件替换旧版本,并重启 MongoDB 服务。在生产环境更新时,要遵循一定的部署策略,如滚动升级,以确保服务的连续性。
  1. 漏洞扫描与修复
    • 使用漏洞扫描工具如 Nessus 或 OpenVAS 对运行 MongoDB 的服务器进行定期扫描。这些工具可以检测出 MongoDB 相关的已知漏洞。
    • 当发现漏洞时,根据漏洞的严重程度和影响范围,及时采取修复措施。如果是 MongoDB 本身的漏洞,及时更新到包含修复的版本;如果是配置相关的漏洞,如弱密码或不安全的网络配置,按照前面介绍的安全配置方法进行修复。

通过以上全面的安全性配置与增强措施,可以有效提升 MongoDB 副本集的安全性,保护数据的机密性、完整性和可用性。在实际应用中,要根据业务需求和安全要求,灵活运用这些方法,并持续关注安全动态,及时调整安全策略。