Appearance
MongoDB 安全性
MongoDB提供了多层次的安全机制,包括认证、授权、加密和网络安全等。本章详细介绍MongoDB的安全特性、配置方法和最佳实践。
安全基础概念
MongoDB安全模型
MongoDB的安全模型包含以下几个关键方面:
- 认证:验证用户身份
- 授权:控制用户权限
- 加密:保护数据传输和存储
- 网络安全:控制网络访问
安全原则
- 最小权限原则
- 纵深防御
- 安全默认配置
认证机制
1. SCRAM(Salted Challenge Response Authentication Mechanism)
SCRAM是MongoDB推荐的认证机制,包括SCRAM-SHA-1和SCRAM-SHA-256。
javascript
// 创建使用SCRAM认证的用户
use admin
db.createUser({
user: "admin",
pwd: "secure_password",
roles: [
{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" },
{ role: "dbAdminAnyDatabase", db: "admin" }
]
})
// 连接时使用SCRAM认证
mongo --username admin --password secure_password --authenticationDatabase admin
2. X.509证书认证
X.509认证使用TLS/SSL证书进行身份验证。
bash
# 启动mongod时启用X.509认证
mongod --auth --setParameter "authenticationMechanisms=X509" \
--sslMode requireSSL \
--sslPEMKeyFile /path/to/server.pem \
--sslCAFile /path/to/ca.pem
javascript
// 创建X.509用户
db.getSiblingDB("$external").runCommand({
createUser: "CN=myName,O=myOrg",
roles: [
{ role: "readWrite", db: "myDatabase" },
{ role: "userAdmin", db: "myDatabase" }
],
writeConcern: { w: "majority", wtimeout: 5000 }
})
3. LDAP认证(企业版)
javascript
// 配置LDAP认证
db.createRole({
role: "ldapUser",
privileges: [
{ resource: { db: "reports", collection: "users" }, actions: ["find"] }
],
roles: []
})
授权和角色管理
内置角色
javascript
// 数据库用户角色
db.createUser({
user: "appUser",
pwd: "password",
roles: [
{ role: "readWrite", db: "appDatabase" },
{ role: "dbAdmin", db: "appDatabase" }
]
})
// 读取角色
db.createUser({
user: "readOnlyUser",
pwd: "password",
roles: [
{ role: "read", db: "appDatabase" },
{ role: "read", db: "logsDatabase" }
]
})
// 集群管理角色
db.createUser({
user: "clusterAdmin",
pwd: "password",
roles: [
{ role: "clusterAdmin", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" }
]
})
自定义角色
javascript
// 创建自定义角色
use appDatabase
db.createRole({
role: "reportReader",
privileges: [
{
resource: { db: "appDatabase", collection: "reports" },
actions: ["find", "collStats"]
},
{
resource: { db: "appDatabase", collection: "users" },
actions: ["find"]
}
],
roles: []
})
// 为用户分配自定义角色
db.createUser({
user: "reportUser",
pwd: "password",
roles: [
{ role: "reportReader", db: "appDatabase" },
{ role: "read", db: "admin" }
]
})
角色继承
javascript
// 创建基于现有角色的新角色
db.createRole({
role: "enhancedReader",
privileges: [
{
resource: { db: "appDatabase", collection: "sensitive" },
actions: ["find"]
}
],
roles: [
{ role: "read", db: "appDatabase" },
{ role: "read", db: "logsDatabase" }
]
})
网络安全
绑定IP地址
bash
# 限制MongoDB绑定的IP地址
mongod --bind_ip 127.0.0.1,192.168.1.100
# 或在配置文件中设置
# /etc/mongod.conf
net:
bindIp: 127.0.0.1,192.168.1.100
port: 27017
防火墙配置
bash
# Linux防火墙配置示例
sudo ufw allow from 192.168.1.0/24 to any port 27017
sudo iptables -A INPUT -s 192.168.1.0/24 -p tcp --destination-port 27017 -j ACCEPT
TLS/SSL加密
配置TLS/SSL
bash
# 启用TLS/SSL连接
mongod --sslMode requireSSL \
--sslPEMKeyFile /path/to/server.pem \
--sslCAFile /path/to/ca.pem \
--sslAllowConnectionsWithoutCertificates
# 客户端连接
mongo --ssl \
--sslPEMKeyFile /path/to/client.pem \
--sslCAFile /path/to/ca.pem \
--host mongodb.example.com
配置文件方式
yaml
# /etc/mongod.conf
net:
port: 27017
ssl:
mode: requireSSL
PEMKeyFile: /path/to/server.pem
CAFile: /path/to/ca.pem
allowConnectionsWithoutCertificates: false
allowInvalidCertificates: false
allowInvalidHostnames: false
应用程序TLS配置
javascript
// Node.js TLS配置
const { MongoClient } = require('mongodb');
const client = new MongoClient('mongodb://mongodb.example.com:27017', {
ssl: true,
sslValidate: true,
sslCA: fs.readFileSync('/path/to/ca.pem'),
sslCert: fs.readFileSync('/path/to/client-cert.pem'),
sslKey: fs.readFileSync('/path/to/client-key.pem'),
authMechanism: 'MONGODB-X509',
authSource: '$external'
});
字段级加密
客户端字段级加密
javascript
// 安装加密扩展
const { MongoClient } = require('mongodb');
const { ClientEncryption } = require('mongodb-client-encryption');
// 配置加密
const keyVaultNamespace = 'encryption.__keyVault';
const kmsProviders = {
local: {
key: fs.readFileSync('/path/to/local-key.txt')
}
// 或其他KMS提供商:aws, azure, gcp
};
const clientEncryption = new ClientEncryption(client, {
keyVaultNamespace,
kmsProviders
});
// 创建数据加密密钥
const dek = await clientEncryption.createDataKey('local');
// 使用加密插入文档
const encryptedClient = client.connect({
autoEncryption: {
keyVaultNamespace,
kmsProviders,
schemaMap: {
'mydb.mycollection': {
bsonType: 'object',
properties: {
'encryptedField': {
encrypt: {
bsonType: 'string',
algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random',
keyId: [dek]
}
}
}
}
}
}
});
// 插入加密数据
db.mycollection.insertOne({
name: 'John Doe',
encryptedField: 'sensitive data' // 自动加密
});
数据加密
静态数据加密
storage:
engine: wiredTiger
wiredTiger:
engineConfig:
configString: 'encryption=(secretkey=file:///path/to/encryption/key)'
密钥管理
javascript
// 使用外部密钥管理
const kmsProviders = {
aws: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
},
azure: {
tenantId: process.env.AZURE_TENANT_ID,
clientId: process.env.AZURE_CLIENT_ID,
clientSecret: process.env.AZURE_CLIENT_SECRET
},
gcp: {
email: process.env.GCP_EMAIL,
privateKey: process.env.GCP_PRIVATE_KEY
}
};
审计日志
启用审计日志
# /etc/mongod.conf
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/auditLog.json
filter: '{ atype: { $in: [ "createUser", "dropUser", "grantRole", "revokeRole", "authenticate" ] } }'
审计过滤器
// 审计登录尝试
{
atype: "authenticate",
result: { $ne: 0 } // 记录失败的认证尝试
}
// 审计数据修改
{
atype: { $in: ["insert", "update", "delete"] },
"param.ns": { $regex: "^myapp\\." }
}
// 审计用户管理
{
atype: { $in: ["createUser", "dropUser", "grantRole", "revokeRole"] }
}
安全配置
安全参数设置
# /etc/mongod.conf
setParameter:
# 限制内嵌文档深度
maxRecursionDepth: 32
# 限制数组大小
maxArraySize: 16000000
# 限制BSON对象大小
maxBSONSize: 16777216
# 禁用eval
enableLocalhostAuthBypass: false
禁用危险操作
// 禁用eval和类似操作
db.adminCommand({
setParameter: 1,
enableJavaScript: false // 禁用服务器端JavaScript
})
应用程序安全
连接字符串安全
// 安全的连接字符串
const uri = "mongodb://username:password@host1:27017,host2:27017,host3:27017/database?" +
"authSource=admin&" +
"ssl=true&" +
"replicaSet=myReplSet&" +
"readPreference=secondaryPreferred&" +
"retryWrites=true";
// 避免在代码中硬编码凭证
const client = new MongoClient(uri, {
auth: {
username: process.env.DB_USER,
password: process.env.DB_PASS
}
});
输入验证
// 应用程序层面的输入验证
function validateQuery(query) {
// 防止查询注入
if (typeof query !== 'object' || Array.isArray(query)) {
throw new Error('Invalid query format');
}
// 检查是否包含危险操作符
const dangerousOps = ['$where', '$regex', '$expr'];
for (const op of dangerousOps) {
if (op in query) {
throw new Error(`Dangerous operator ${op} not allowed`);
}
return query;
}
// 使用参数化查询
const userId = sanitizeInput(userInput);
const user = await db.users.findOne({ _id: ObjectId(userId) });
安全监控
监控安全事件
// 监控认证失败
db.system.profile.find({
"command.authenticate": { $exists: true },
"millis": { $gte: 1000 }
}).sort({ ts: -1 })
// 监控权限不足的访问
db.system.profile.find({
"errInfo.code": 13 // Authorization error
}).sort({ ts: -1 })
// 监控模式变更
db.system.profile.find({
"command.create": { $exists: true },
"command.drop": { $exists: true },
"command.renameCollection": { $exists: true }
}).sort({ ts: -1 })
安全指标
// 监控脚本
function monitorSecurity() {
// 认证失败统计
const authFailures = db.system.profile.countDocuments({
"command.authenticate": { $exists: true },
"result": { $ne: 0 }
});
// 高权限用户活动
const adminActivities = db.system.profile.countDocuments({
"command.createIndex": { $exists: true },
"command.drop": { $exists: true }
});
// 异常查询模式
const slowQueries = db.system.profile.countDocuments({
"millis": { $gte: 5000 }
});
return {
authFailures,
adminActivities,
slowQueries
};
}
安全最佳实践
1. 身份验证和授权
// 创建最小权限用户
db.createUser({
user: "app_user",
pwd: "strong_password",
roles: [
{ role: "readWrite", db: "app_db" } // 只授予必要权限
]
})
// 定期轮换密码
db.changeUserPassword("app_user", "new_strong_password")
2. 网络安全
# 使用VPN或专用网络
# 配置防火墙规则
iptables -A INPUT -s trusted_network -p tcp --dport 27017 -j ACCEPT
iptables -A INPUT -p tcp --dport 27017 -j DROP
# 启用TLS/SSL
mongod --sslMode requireSSL --sslPEMKeyFile /path/to/cert.pem
3. 数据保护
// 敏感数据加密
const encryptedData = encrypt(sensitiveInfo, encryptionKey);
// 数据脱敏
function maskSensitiveData(doc) {
if (doc.creditCard) {
doc.creditCard = '****-****-****-' + doc.creditCard.slice(-4);
}
return doc;
}
4. 安全配置
# 安全的mongod配置
net:
port: 27017
bindIp: 127.0.0.1 # 仅本地访问,或指定可信IP
ssl:
mode: requireSSL
security:
authorization: enabled # 启用认证授权
javascriptEnabled: false # 禁用服务器端JavaScript
setParameter:
enableLocalhostAuthBypass: false # 禁用本地认证绕过
漏洞防护
1. 注入攻击防护
// 避防查询注入
function safeFind(collection, fieldName, value) {
// 验证字段名
if (!isValidFieldName(fieldName)) {
throw new Error('Invalid field name');
}
// 使用参数化查询
return collection.findOne({ [fieldName]: value });
}
// 验证函数
function isValidFieldName(name) {
// 只允许字母、数字、下划线
return /^[a-zA-Z0-9_]+$/.test(name);
}
2. 拒绝服务防护
// 实现查询限制
const MAX_RESULTS = 1000;
const TIMEOUT_MS = 5000;
db.collection.find(query)
.limit(MAX_RESULTS)
.maxTimeMS(TIMEOUT_MS);
合规性
GDPR合规
// 数据删除实现
function gdprDelete(userId) {
// 删除用户数据
db.users.deleteOne({ _id: userId });
// 删除相关数据
db.orders.deleteMany({ userId: userId });
db.logs.deleteMany({ userId: userId });
// 记录删除操作
db.audit.insertOne({
action: 'gdpr_delete',
userId: userId,
timestamp: new Date(),
deletedBy: getCurrentUser()
});
}
审计追踪
// 操作审计
function auditedUpdate(collection, filter, update) {
const auditEntry = {
operation: 'update',
collection: collection.collectionName,
filter: filter,
update: update,
timestamp: new Date(),
user: getCurrentUser()
};
// 先记录审计日志
db.audit.insertOne(auditEntry);
// 执行更新操作
return collection.updateOne(filter, update);
}
安全工具
1. MongoDB安全检查器
# 使用MongoDB安全检查器
mongod --setParameter "enableTestCommands=1"
# 或使用第三方安全扫描工具
2. 密码策略
// 密码强度验证
function validatePassword(password) {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
return password.length >= minLength &&
hasUpperCase &&
hasLowerCase &&
hasNumbers &&
hasSpecialChar;
}
总结
MongoDB安全性是一个综合性的课题,需要从多个层面进行考虑:
- 认证授权:实现强身份验证和最小权限访问
- 网络安全:使用TLS/SSL和适当的网络配置
- 数据保护:实现数据加密和访问控制
- 监控审计:持续监控安全事件和合规性
- 最佳实践:遵循安全配置和开发实践
通过综合运用这些安全措施,可以构建安全可靠的MongoDB部署。