Skip to content
On this page

MongoDB 安全性

MongoDB提供了多层次的安全机制,包括认证、授权、加密和网络安全等。本章详细介绍MongoDB的安全特性、配置方法和最佳实践。

安全基础概念

MongoDB安全模型

MongoDB的安全模型包含以下几个关键方面:

  1. 认证:验证用户身份
  2. 授权:控制用户权限
  3. 加密:保护数据传输和存储
  4. 网络安全:控制网络访问

安全原则

  • 最小权限原则
  • 纵深防御
  • 安全默认配置

认证机制

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安全性是一个综合性的课题,需要从多个层面进行考虑:

  1. 认证授权:实现强身份验证和最小权限访问
  2. 网络安全:使用TLS/SSL和适当的网络配置
  3. 数据保护:实现数据加密和访问控制
  4. 监控审计:持续监控安全事件和合规性
  5. 最佳实践:遵循安全配置和开发实践

通过综合运用这些安全措施,可以构建安全可靠的MongoDB部署。