一、MongoDB默认安全设置的那些坑
刚接触MongoDB时,很多人会觉得它开箱即用特别方便——不用像传统数据库那样折腾用户权限,甚至默认连密码都不设。但这种"方便"背后藏着大问题:2017年就有公司因为MongoDB默认配置漏洞,导致数TB用户数据被黑客清空勒索。下面这段连接代码展示了典型的风险操作:
// 危险示例:使用默认配置连接MongoDB(技术栈:Node.js + MongoDB驱动)
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017'; // 无认证连接
async function main() {
const client = new MongoClient(url);
try {
await client.connect();
console.log('成功连接到数据库!');
// 任何人都可以在这里执行任意操作...
} finally {
await client.close();
}
}
main().catch(console.error);
这种配置下,攻击者只需要知道服务器IP,就能像操作自己电脑一样随意增删改查数据。更可怕的是,MongoDB默认会监听所有网络接口(0.0.0.0),相当于把大门敞开给整个互联网。
二、加固必须做的四件事
1. 启用访问控制
启动MongoDB服务时一定要加上--auth参数,或者在配置文件中设置security.authorization: enabled。但要注意顺序:
# 正确流程(技术栈:Linux系统管理)
# 1. 先以无认证模式启动
mongod --port 27017 --dbpath /data/db
# 2. 创建管理员(在mongo shell中执行)
use admin
db.createUser({
user: "superadmin",
pwd: "ComplexP@ssw0rd!2023", // 实际使用中要用更强密码
roles: ["root"]
})
# 3. 关闭服务后重新启用认证
mongod --auth --port 27017 --dbpath /data/db
2. 网络层隔离
生产环境务必修改默认端口,并通过防火墙限制访问源:
// 安全连接示例(技术栈:Node.js)
const secureUrl = 'mongodb://superadmin:ComplexP@ssw0rd!2023@localhost:27018/admin?authSource=admin';
// 注意三个关键点:
// 1. 使用非默认端口27018
// 2. 指定认证数据库为admin
// 3. 连接字符串包含用户名密码
3. 加密传输配置
TLS加密是防止中间人攻击的关键,配置示例:
# mongod.conf 关键配置(技术栈:MongoDB配置文件)
net:
ssl:
mode: requireSSL
PEMKeyFile: /etc/ssl/mongodb.pem
CAFile: /etc/ssl/ca.pem
bindIp: 127.0.0.1 # 只允许本地连接
4. 精细化权限控制
不要所有用户都用admin权限,应该按需分配:
// 创建应用专用用户(在mongo shell中执行)
use appdb
db.createUser({
user: "appuser",
pwd: "App@Secure123",
roles: [
{ role: "readWrite", db: "appdb" },
{ role: "read", db: "reportdb" }
]
})
三、进阶防护策略
1. 审计日志配置
记录所有敏感操作,配置示例:
# mongod.conf 审计配置
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/audit.json
filter: '{ "users": { $exists: true } }'
2. 数据字段级加密
使用MongoDB的客户端字段级加密(CSFLE):
// 字段加密示例(技术栈:Node.js)
const { ClientEncryption } = require('mongodb-client-encryption');
const encryption = new ClientEncryption(client, {
keyVaultNamespace: 'encryption.__keyVault',
kmsProviders: {
local: { key: Buffer.from('32字节长的密钥...', 'utf-8') }
}
});
// 加密身份证号字段
const encryptedId = await encryption.encrypt(
'1234567890',
{
algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic',
keyId: keyId
}
);
3. 定期安全扫描
使用mongodb-security-checklist工具:
# 安全扫描示例(技术栈:Linux命令行)
docker run --rm -it ghcr.io/stamparm/mongodb-security-checklist \
-h your.mongo.host -p 27017 -u admin -p 'yourpassword'
四、常见问题解决方案
1. 连接数暴增问题
突然出现大量连接可能是扫描攻击,解决方案:
# mongod.conf 连接限制
net:
maxIncomingConnections: 500
serviceExecutor: 'adaptive'
2. 认证失败排查
当遇到Authentication failed错误时,检查:
// 诊断脚本(技术栈:Node.js)
const { MongoClient } = require('mongodb');
const uri = 'mongodb://wrong:password@localhost:27017/admin?authMechanism=SCRAM-SHA-1';
MongoClient.connect(uri, {
serverSelectionTimeoutMS: 5000,
authMechanism: 'SCRAM-SHA-256' // 明确指定认证机制
}).catch(err => {
console.error('认证失败原因:', err.message);
// 常见错误:
// - MONGODB-CR已废弃
// - 用户名包含特殊字符
// - 密码过期
});
3. 备份加密策略
即使是备份文件也要加密:
# 加密备份示例(技术栈:Linux + OpenSSL)
mongodump --uri="mongodb://user:pwd@localhost:27017/dbname" \
--archive | openssl enc -aes-256-cbc -salt -out backup.enc -k "密码"
五、不同场景下的最佳实践
1. 开发环境配置
虽然开发环境可以放宽限制,但仍需基础防护:
# Docker开发环境示例(技术栈:Docker)
version: '3'
services:
mongo:
image: mongo:5.0
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: devadmin
MONGO_INITDB_ROOT_PASSWORD: Dev@Password123
command: ["--bind_ip_all", "--auth"]
2. 云服务特殊配置
AWS DocumentDB等云服务有额外要求:
// 云服务连接示例(技术栈:Node.js)
const { MongoClient } = require('mongodb');
const uri = 'mongodb://user:password@docdb-2023.cluster.us-east-1.docdb.amazonaws.com:27017/?ssl=true&ssl_ca_certs=rds-combined-ca-bundle.pem&replicaSet=rs0';
// 特别注意:
// 1. 必须使用TLS
// 2. 需要下载特定的CA证书
// 3. 要指定replicaSet名称
3. 容器化部署要点
Kubernetes环境需要特别注意:
# Kubernetes ConfigMap示例(技术栈:K8s)
apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-config
data:
mongod.conf: |
security:
authorization: enabled
keyFile: /etc/mongodb-keyfile
net:
bindIp: 0.0.0.0
port: 27017
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/tls.crt
六、安全加固效果验证
完成所有配置后,建议用以下方法验证:
// 安全测试脚本(技术栈:Node.js)
const insecureChecks = [
{ desc: '测试匿名访问', cmd: { listDatabases: 1 } },
{ desc: '测试未加密连接', uri: 'mongodb://localhost:27017' }
];
insecureChecks.forEach(async test => {
try {
const client = new MongoClient(test.uri || 'mongodb://localhost:27017');
await client.connect();
const result = await client.db().admin().command(test.cmd);
console.error(`[危险] ${test.desc} 成功!`);
} catch (e) {
console.log(`[安全] ${test.desc} 已拦截: ${e.message}`);
}
});
七、总结与持续防护
安全加固不是一次性的工作,需要:
- 每季度审查用户权限
- 及时安装安全补丁
- 监控异常查询模式
- 定期演练灾难恢复
最后记住:默认安全≠安全,数据库安全需要主动配置和持续维护。从今天开始,检查你的MongoDB配置是否还"裸奔"在互联网上吧!
评论