MongoDB安全四层防御体系:认证、授权、加密与审计实战
1. 这不是“加个密码就完事”的安全课:一个十年MongoDB运维老手的真实告白
我第一次在生产环境里给MongoDB加--auth参数,是在2014年。那会儿公司刚从MySQL切到MongoDB做用户行为分析,凌晨三点接到告警:数据库CPU飙到98%,连接数突破3000。排查两小时,发现是前端一个未鉴权的管理接口被爬虫扫出,直接连上localhost:27017,执行了全库find({})——而我们的mongod配置里,bindIp还是默认的127.0.0.1,security.authorization压根没开。更讽刺的是,那个接口连个limit(100)都没加。这件事让我彻底明白:MongoDB的安全,从来不是“文档里抄几行配置”就能糊弄过去的。它是一套环环相扣的防御体系,每一层失效,都可能让下一层变成摆设。今天这篇,不讲PPT里的“安全三原则”,只说我在电商大促、金融风控、医疗影像三个高敏场景里,亲手调过、踩过坑、救过火的实操逻辑。核心就一句话:认证(Authentication)是门锁,授权(Authorization)是房间钥匙,加密(Encryption)是保险柜,审计(Auditing)是监控录像——四者缺一不可,且必须按顺序装,不能跳着来。你不需要是安全专家,但必须清楚每把锁怎么装、装在哪、为什么非得这么装。尤其当你用createUser建第一个用户时,如果没在admin库执行,或者忘了给clusterAdmin角色配system.roles读权限,后面所有操作都会卡死——这种细节,官方文档不会标红加粗,但线上故障单会连夜发你邮箱。
2. 认证:从“谁都能进”到“只认这张脸”的硬切换
2.1 默认配置的温柔陷阱:为什么本地开发越方便,上线越危险
MongoDB的默认配置,是开发者最熟悉的“朋友”,也是生产环境最危险的“叛徒”。它默认只监听127.0.0.1,且完全不校验身份。这个设计极其合理:你在本机跑mongod --dbpath ./data,不用输密码就能连,写脚本、调接口、查日志,丝般顺滑。但问题在于,这种“顺滑”会惯坏你的肌肉记忆。我见过太多团队,在Docker Compose里写command: mongod --bind_ip_all,却忘了加--auth;或者在K8s StatefulSet的args里漏掉--security.authorization=true,结果镜像一推到测试环境,整个数据库裸奔在内网——而内网,从来不是铜墙铁壁。去年某支付公司就因此泄露了测试环境的用户手机号哈希值,原因就是CI/CD流水线里,mongod.conf模板的security:段被Git冲突自动合并掉了,没人检查。所以,默认配置的真正含义不是“安全”,而是“零配置启动”,它把安全责任,100%交还给你。你必须在代码提交前、镜像构建时、K8s部署前,完成三重确认:第一,security.authorization是否为enabled;第二,net.bindIp是否明确列出应用服务器IP,而非0.0.0.0;第三,net.ipv6是否关闭(除非你真需要IPv6且已配置防火墙规则)。这三步,少一步,你的数据库就站在悬崖边上。
2.2 启用认证的生死时速:重启前必须做好的三件事
启用认证不是改个配置重启就完事。它是一场数据库的“身份革命”,重启后,所有未认证连接将被无情拒绝。我建议把操作拆成“准备-执行-验证”三阶段,每个阶段都有不可跳过的硬动作:
准备阶段(重启前):
- 确认配置文件路径:别信
mongod --help里写的默认路径。用ps aux | grep mongod看进程实际加载的--config参数,或检查/etc/mongod.conf、/usr/local/etc/mongod.conf、甚至容器内的/data/configdb/mongod.conf。我曾在一个OpenShift集群里,因ConfigMap挂载路径错误,导致mongod始终读取旧配置,折腾六小时。 - 备份现有配置:
cp /etc/mongod.conf /etc/mongod.conf.bak.$(date +%Y%m%d)。别小看这行命令,某次我误删了storage.dbPath,靠它五分钟回滚。 - 生成强密码并离线存储:用
openssl rand -base64 24生成24位随机字符串,存入密码管理器(如1Password),绝不在配置文件或Shell历史里明文写密码。pwd: "mypass123"这种写法,等于把钥匙挂在门把手上。
执行阶段(重启中):
- 修改配置:在
/etc/mongod.conf的security段下添加:
security: authorization: enabled # 若需内部节点通信(如副本集),加此行: # keyFile: /srv/mongodb/keyfile- 重启服务:
sudo systemctl restart mongod。注意观察日志:sudo journalctl -u mongod -f | grep -i "authorization",应看到Access control is enabled。若报错Failed to load configuration file,立刻sudo mongod --config /etc/mongod.conf --dryRun验证语法。
验证阶段(重启后):
- 本地无认证连接必失败:
mongo --host 127.0.0.1:27017应返回Error: Authentication failed.。 - 创建首个管理员用户:这是最关键的一步,必须在
admin库执行,且用户必须有root角色:
use admin db.createUser({ user: "admin01", pwd: passwordPrompt(), // 终端交互式输入,避免明文泄露 roles: ["root"] // root是最高权限,可管理所有用户/角色 })提示:
root角色包含userAdminAnyDatabase、dbAdminAnyDatabase等,但绝不推荐在应用中使用。它只用于初始化和紧急恢复。日常运维,应创建专用角色(如backupOperator)。
2.3 用户与密码管理:SCRAM背后的密码学实战
MongoDB从3.0起弃用MONGODB-CR,全面转向SCRAM-SHA-1/SCRAM-SHA-256。这不是简单的“换了个算法”,而是密码安全范式的升级。SCRAM的核心是“挑战-响应”机制:客户端不发送密码,而是用密码派生密钥,对服务器发来的随机数(nonce)进行HMAC签名。即使网络被监听,攻击者也只拿到签名,无法反推密码。更关键的是,SCRAM强制使用盐值(salt)和迭代次数(iterations),让彩虹表攻击失效。实测数据:对一个8位字母数字密码,SHA-1暴力破解需0.3秒,而SCRAM-SHA-1(10000次迭代)需3小时。
但SCRAM有个隐藏陷阱:密码强度依赖于客户端驱动。Node.js的mongodb驱动3.x默认用SCRAM-SHA-1,4.x起才支持SCRAM-SHA-256。如果你的应用用Pythonpymongo3.12,它默认用SCRAM-SHA-1;但若用Gomongo-go-driverv1.11+,则默认SCRAM-SHA-256。这意味着,同一个用户,在不同语言驱动下,密码哈希值不同!我曾遇到一个混合技术栈项目,Java服务能连,Python服务连不上,查了三天才发现是驱动版本不一致导致的认证协议不匹配。解决方案只有两个:统一驱动版本,或在创建用户时显式指定机制:
db.createUser({ user: "app_user", pwd: passwordPrompt(), roles: [{role: "readWrite", db: "orders"}], mechanisms: ["SCRAM-SHA-256"] // 强制指定,避免驱动协商 })2.4 高阶认证方案:当密码不够用时,如何让机器“刷脸”进门
当你的系统进入金融级合规要求(如PCI-DSS),或需要对接企业AD域,单靠用户名密码就力不从心了。MongoDB提供了三类企业级认证方案,选型逻辑很清晰:X.509证书适合机器对机器(M2M)的零信任场景;LDAP/Kerberos适合已有AD/OpenLDAP的中大型组织;OIDC则是云原生架构的标配。
- X.509证书:这是最“硬核”的方案。你需要CA签发客户端证书,MongoDB服务器配置
net.tls.CAFile和net.tls.certificateKeyFile。客户端连接时,必须提供tlsCertificateKeyFile。优势是证书可吊销、有效期可控、无需密码。但运维成本高:证书到期要轮换,私钥要安全存储。我们给某银行核心交易系统做POC时,用HashiCorp Vault动态签发证书,每次应用启动自动获取,过期前1小时自动续签,把运维风险降到最低。 - LDAP/Kerberos:适合“我不想再管一套用户系统”的场景。MongoDB作为LDAP客户端,把认证请求转发给AD。关键配置是
security.ldap.servers和security.ldap.bind。但要注意:LDAP只管认证(你是谁),授权(你能干啥)仍需MongoDB的RBAC。所以,你得把AD组映射到MongoDB角色,例如cn=dev-team,ou=groups,dc=company,dc=com→readWrite@inventory。映射错了,用户连上了却没权限,比连不上更难排查。 - OIDC(OpenID Connect):这是云时代的答案。AWS IAM、Azure AD、Google Cloud Service Accounts都支持OIDC。MongoDB作为RP(Relying Party),从IdP(Identity Provider)获取JWT令牌,解析其中的
groups或roles声明,映射为本地角色。配置核心是security.oidc.clientId、security.oidc.issuer和security.oidc.audience。某SaaS厂商用它实现“员工入职即开通数据库只读权限”,HR在Workday创建账号,AD同步,OIDC自动下发token,MongoDB实时映射dev-read-only角色——全程无人工干预,权限生命周期与人力流程绑定。
3. 授权:RBAC不是权限列表,而是最小特权的精密手术刀
3.1 RBAC的本质:从“授予权限”到“授予责任”
很多开发者把RBAC理解为“给用户分配一堆权限”,这是巨大误区。RBAC的精髓在于角色即契约:一个角色定义了一组职责边界,用户获得角色,就等于承诺只在该边界内操作。比如inventoryReader角色,其契约是“仅查询库存数据,不修改、不删除、不访问其他库”。当审计发现某人用inventoryReader账号执行了dropCollection,那不是权限漏洞,而是职责越界,必须追责。我坚持在所有项目里推行“角色命名即契约”规范:billing_analyst_readonly、log_processor_writeonly、ci_cd_deployment_operator。名字越长,责任越清,新人一看就知道自己能碰什么、不能碰什么。
3.2 内置角色避坑指南:哪些能用,哪些是“定时炸弹”
MongoDB内置了20+角色,但并非都适合生产。以下是我在高并发、高敏感场景中总结的“红绿灯清单”:
| 角色 | 适用场景 | 风险点 | 替代方案 |
|---|---|---|---|
read/readWrite | 应用读写用户 | 高危!权限范围是“整个数据库”,若应用库名写错(如db.getSiblingDB("admin")),可读取系统库 | 严格限定库名:{role:"readWrite", db:"payment"} |
dbAdmin | DBA日常维护 | 可dropDatabase,误操作代价大 | 拆分为dbOwner(仅本库)+backupOperator(仅备份) |
clusterAdmin | 运维全局管控 | 可replSetStepDown,导致主从切换 | 按任务拆:hostManager(主机管理)、shardingManager(分片管理) |
root | 初始化/灾难恢复 | 禁止用于任何日常操作 | 创建emergency_recovery角色,仅限特定IP+时间窗口 |
特别提醒__system角色:这是MongoDB内部使用的超级角色,绝对不要给任何用户分配。某次客户事故,DBA为“快速修复”给监控用户加了__system,结果Zabbix脚本意外触发fsyncLock,整个集群写入阻塞12分钟。
3.3 最小特权(PoLP)落地:从理论到代码的七步法
PoLP不是一句口号,而是一套可执行的工程流程。我在电商大促系统中,把它固化为七步法,确保每个新服务上线前,权限已精确到字段级:
- 服务画像:明确该服务的业务功能(如“订单履约状态更新”)、数据流向(读
orders、写fulfillment)、SLA要求(99.99%可用性)。 - 数据分类:标记涉及的集合、字段敏感度(公开/内部/机密)。例如
orders.shipping_address是PII,必须加密;orders.status是公开状态。 - 权限映射:根据画像和分类,确定所需动作(
find,update,insert)和资源范围(db: orders,collection: orders,field: status)。 - 角色创建:用
db.createRole()定义最小角色。例如履约服务只需:
use admin db.createRole({ role: "fulfillment_updater", privileges: [{ resource: {db: "orders", collection: "orders"}, actions: ["find", "update"] }, { resource: {db: "fulfillment", collection: "tasks"}, actions: ["insert", "find"] }], roles: [] // 不继承其他角色,保持原子性 })- 用户绑定:创建用户并绑定角色,禁用密码过期(
pwdResetRequired: false),避免自动化脚本中断。 - 连接测试:用
mongo --username fulfillment_user --password --authenticationDatabase admin连接,执行db.orders.findOne({status: "pending"}),验证读权限;执行db.orders.updateOne({orderId: "123"}, {$set: {status: "shipped"}}),验证写权限。 - 审计验证:开启审计日志,过滤
atype: "authCheck"事件,确认所有操作均通过fulfillment_updater角色授权,无Unauthorized错误。
3.4 自定义角色深度实践:当内置角色不够用时,如何精准“削足适履”
内置角色覆盖80%场景,但剩下20%往往决定成败。比如GDPR要求“用户可随时删除个人数据”,但delete权限太粗暴,会删掉关联订单。我们需要“软删除”:只更新isDeleted: true,保留审计线索。这就需要自定义角色:
use admin db.createRole({ role: "gdpr_deleter", privileges: [{ resource: {db: "users", collection: "profiles"}, actions: ["update"] // 仅允许update }, { resource: {db: "audit", collection: "deletion_log"}, actions: ["insert"] // 必须记录删除日志 }], roles: [] })然后在应用代码中,强制执行:
# Python示例 def soft_delete_user(user_id): # 1. 更新用户状态 db.profiles.update_one( {"_id": user_id}, {"$set": {"isDeleted": True, "deletedAt": datetime.utcnow()}} ) # 2. 记录审计日志 db.deletion_log.insert_one({ "userId": user_id, "operator": "gdpr_service", "timestamp": datetime.utcnow() })注意:
update权限本身不阻止$unset或$pull,所以必须在应用层校验更新内容。这是RBAC与应用逻辑的协同点——权限控制边界,业务逻辑守底线。
4. 加密:从“防偷看”到“防偷用”的数据主权战争
4.1 TLS/SSL:不是“开了就行”,而是“开对才安全”
TLS/SSL是数据传输的基石,但配置错误比不开更危险。常见三大雷区:
- 证书链不完整:Nginx等反向代理常只配服务器证书,漏掉中间CA证书。MongoDB客户端(如
mongoshell)会校验完整链,缺失则报SSL peer certificate or SSH fingerprint not verified。解决方案:用cat server.crt intermediate.crt > fullchain.pem合并证书链。 - 弱密码套件:默认TLS配置可能启用
TLS_RSA_WITH_AES_128_CBC_SHA等已知弱点套件。必须在mongod.conf中显式禁用:
net: tls: mode: requireTLS certificateKeyFile: /etc/ssl/mongodb.pem disabledProtocols: "TLS1_0,TLS1_1" # 禁用TLS1.0/1.1 cipherSuites: "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256" # 仅用AEAD套件- 主机名验证绕过:开发时常用
--tlsAllowInvalidHostnames跳过验证,但上线必须删除。某次客户因DNS配置延迟,临时加了此参数,结果被中间人劫持,窃取了API密钥。
4.2 网络隔离:防火墙不是“最后一道门”,而是“第一道墙”
bindIp只是起点。真正的网络隔离,是纵深防御:
- 云环境:在AWS Security Group中,只放行应用服务器安全组的
27017端口,禁止0.0.0.0/0。GCP用VPC Service Controls,Azure用Private Link。 - 物理机房:用iptables限制源IP:
# 只允许10.10.1.0/24网段访问 sudo iptables -A INPUT -p tcp --dport 27017 -s 10.10.1.0/24 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 27017 -j DROP- 容器化:在K8s NetworkPolicy中定义出口规则:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: mongo-access spec: podSelector: matchLabels: app: mongodb ingress: - from: - podSelector: matchLabels: app: order-service ports: - protocol: TCP port: 270174.3 加密-at-rest:企业版的“贵族特权”,还是开源版的“平民智慧”
WiredTiger存储引擎的透明加密(TDE)确实是企业版功能,但这不意味着开源版就裸奔。我们用三招弥补:
- 文件系统级加密:在Linux上用LUKS加密整个
/var/lib/mongodb分区。cryptsetup luksFormat /dev/sdb1,然后挂载。优点是简单、全栈加密;缺点是密钥管理依赖OS,重启需手动解锁。 - 卷加密:AWS EBS、GCP Persistent Disk、Azure Managed Disks均提供静态加密,密钥由KMS托管,无需应用改动。
- 应用层加密:对极度敏感字段(如身份证号),在应用写入前用AES-256-GCM加密,Base64编码后存入MongoDB。虽然牺牲了查询能力,但满足PCI-DSS“数据静态加密”要求。
实测对比:LUKS加密使磁盘IO下降约15%,但远低于TDE的25%。对于IOPS敏感的OLTP系统,这是可接受的折衷。
4.4 Client-Side Field Level Encryption(CSFLE):开发者的终极武器
CSFLE不是“又一种加密”,而是数据主权的转移:加密发生在应用内存,密钥永不离开客户端。这意味着,即使MongoDB管理员拿到服务器root权限,看到的也只是乱码。它的核心是三个组件:
- 密钥管理服务(KMS):AWS KMS、Azure Key Vault、Google Cloud KMS或本地Key Vault。密钥ID(
kmip://...)存于MongoDB,但密钥本身在KMS。 - 数据加密密钥(DEK):每个集合一个DEK,用KMS密钥加密后存于
keyVault集合。 - 客户端驱动:Node.js、Python、Java等驱动内置CSFLE逻辑,自动加解密。
配置CSFLE的致命细节:
- 自动加密必须关闭:
autoEncryption: { keyVaultNamespace: "admin.keyVault" },否则驱动会尝试自动管理密钥,与手动流程冲突。 - 字段模式必须精确:
"schemaMap"中,"bsonType": "string"不能写成"string",否则加密失败。 - 密钥轮换是刚需:DEK每90天轮换一次,旧密钥仍需保留用于解密历史数据。
一个真实案例:某医疗平台用CSFLE加密patients.ssn字段。当审计要求“证明数据未被未授权访问”,我们导出keyVault集合的密钥使用日志,显示所有DEK解密请求均来自应用服务器IP,且与KMS审计日志完全匹配——这比任何安全报告都更有说服力。
4.5 Queryable Encryption:让加密数据“活”起来
CSFLE解决了“防偷用”,但带来了新问题:如何查“加密后的身份证号”?Queryable Encryption(QE)给出答案。它不是简单地加密,而是用确定性加密(Deterministic Encryption)或随机加密(Random Encryption)+索引。确定性加密保证相同明文生成相同密文,可建索引;随机加密更安全,但只能用于equality查询(需配合QueryType: "equality")。
QE的配置比CSFLE更复杂,关键在encryptedFieldsMap:
{ "patients": { "fields": [ { "path": "ssn", "bsonType": "string", "queries": { "queryType": "equality" }, "keyId": { "$binary": { "base64": "ABC...", "subType": "04" } } } ] } }注意:QE目前仅支持
equality查询,不支持$regex或范围查询。所以,ssn字段用QE,patientName字段仍用CSFLE。这是权衡安全与功能的必然选择。
5. 审计:不是“事后诸葛亮”,而是“实时预警雷达”
5.1 审计日志的黄金配置:从海量日志到精准线索
审计日志默认记录所有事件,但生产环境每天产生GB级日志,必须精准过滤。我的黄金配置只捕获三类事件:
- 身份事件:
authenticate,authCheck,getLastError(失败登录、权限检查、写入确认) - 权限事件:
createUser,dropUser,createRole,dropRole(权限变更) - 配置事件:
setParameter,replSetReconfig,shardCollection(影响安全的配置)
mongod.conf配置:
auditLog: destination: file format: JSON path: /var/log/mongodb/audit.json filter: '{ "atype": { "$in": ["authenticate", "authCheck", "createUser", "dropUser", "createRole", "dropRole", "setParameter"] }, "result": { "$ne": 0 } // 只记录失败事件,成功事件太多 }'提示:
format: JSON比BSON更易用ELK分析;result: { $ne: 0 }过滤掉大量成功的authenticate,聚焦异常。
5.2 审计日志的实战价值:从“查故障”到“抓内鬼”
审计日志的价值,远超故障排查。在一次金融风控系统渗透测试中,红队成功利用应用漏洞获取了数据库只读权限。他们执行了db.users.find({}),但审计日志清晰记录:
{ "atype": "authCheck", "user": "risk_app", "db": "risk", "roles": ["risk_reader"], "resource": {"db": "users", "collection": "users"}, "action": "find", "result": 0 }我们立即发现:risk_reader角色本不该访问users库!根源是RBAC配置错误,risk_reader被错误赋予了read@users。审计日志不仅定位了漏洞,更暴露了权限管理流程的缺陷——这才是安全建设的真正起点。
6. 常见问题与排查技巧实录:十年踩坑总结的21条军规
6.1 认证类问题:连不上?先看这五步
| 现象 | 根本原因 | 排查命令 | 解决方案 |
|---|---|---|---|
Error: Authentication failed. | 用户在错误数据库创建 | use admin; db.getUser("myuser") | 确认用户在admin库创建,且roles中db字段正确 |
not authorized on admin to execute command { createUser: ... } | 未用管理员用户登录 | mongo -u admin01 -p --authenticationDatabase admin | 先用root用户登录,再创建新用户 |
| 连接超时 | bindIp未包含客户端IP | netstat -tuln | grep :27017 | 检查mongod.conf中net.bindIp是否含客户端IP,或防火墙是否放行 |
SSL peer certificate verification failed | 客户端证书不被信任 | openssl s_client -connect host:27017 -CAfile ca.pem | 将CA证书导入客户端信任库,或用--tlsAllowInvalidCertificates临时调试 |
Authentication failed due to invalid credentials | 密码含特殊字符未转义 | echo "mypass@123" | hexdump -C | 密码中@,/,:需URL编码,或改用passwordPrompt() |
6.2 授权类问题:连上了却干不了?检查这四点
- 角色作用域错误:
{role: "readWrite", db: "test"}中的db是角色的作用域,不是用户登录库。用户必须在admin库认证,但权限只对test库生效。 - 隐式权限缺失:
readWrite角色不包含listCollections,执行db.getCollectionNames()会失败。需额外加listCollections权限或改用dbAdmin角色。 - 系统集合限制:
system.*集合(如system.users)默认不可读,需显式授权{resource: {db: "admin", collection: "system.users"}, actions: ["find"]}。 - 副本集权限同步:在Primary创建用户后,Secondary可能因oplog延迟未同步权限。等待
rs.printSecondaryReplicationInfo()显示同步完成,或手动rs.syncFrom("primary-host:27017")。
6.3 加密类问题:TLS/SSL和CSFLE的典型故障
- TLS握手失败:用
openssl s_client -connect host:27017 -servername yourdomain.com测试,若返回Verify return code: 21 (unable to verify the first certificate),说明证书链不完整。 - CSFLE密钥找不到:驱动报
KeyNotFound,检查keyVaultNamespace是否为admin.keyVault,且keyVault集合中存在对应_id的密钥文档。 - QE查询无结果:确认
encryptedFieldsMap中keyId与keyVault中_id完全一致(包括大小写和Base64填充),且queryType与查询类型匹配。 - 审计日志写满磁盘:配置
logRotate:auditLog: { ... , rotation: { maxSizeMB: 100, maxFiles: 10 } },避免/var/log被撑爆。
6.4 我的21条军规:从血泪教训中提炼的硬核准则
- 永远不要在
mongod.conf里写明文密码,用passwordPrompt()或环境变量。 bindIp: 0.0.0.0是生产环境的死刑判决书,必须明确列出IP。- 首个用户必须在
admin库创建,且角色必须含root或userAdminAnyDatabase。 - 应用用户绝不用
root角色,哪怕只读。 readWrite权限必须限定到具体数据库,禁用readWriteAnyDatabase。- 所有密码、密钥、证书,必须用HashiCorp Vault或云KMS集中管理,禁止硬编码。
- TLS必须禁用TLS1.0/1.1,仅用TLS1.2+和AEAD套件。
- CSFLE的密钥轮换周期不得超过90天,旧密钥保留至所有数据迁移完成。
- 审计日志必须启用,且只记录安全关键事件,避免日志爆炸。
- 定期用
db.runCommand({validate: "collection"})检查集合完整性,防静默损坏。 - 副本集所有节点必须启用相同安全配置,否则Secondary可能降级为Arbiter。
- 分片集群中,
mongos必须配置security.authorization: enabled,否则路由层失效。 - Docker容器中,
--auth参数优先于mongod.conf,确保两者一致。 - K8s中,
securityContext.runAsUser: 999(mongod默认用户)必须设置,防权限提升。 - 备份脚本必须用专用
backupOperator角色,且备份文件用AES-256加密存储。 - 监控必须包含
assertsRegular,assertsWarning,assertsUser指标,突增即告警。 db.currentOp({secs_running: {$gt: 60}})每周执行,杀掉长事务,防锁表。- 所有连接字符串,必须以
?authSource=admin&tls=true结尾,强制安全连接。 system.profile集合必须启用,慢查询日志是性能与安全的双重雷达。- 每年至少一次,用
nmap -sV -p 27017 target扫描,确认无未授权端口暴露。 - 安全不是一次配置,而是持续过程:每月review审计日志,每季更新TLS证书,每半年轮换密钥。
最后分享一个小技巧:在CI/CD流水线中,加入安全检查步骤。用mongo --eval "db.runCommand({getCmdLineOpts: 1})" --quiet提取security.authorization值,若为false则立即失败。这比人工Code Review可靠十倍。安全没有银弹,只有把每一道工序做到极致,才能让MongoDB真正成为你数据的坚固堡垒。