安全性
1、安全性介绍
MongoDB数据库的安全性主要通过多种机制和技术来保障,包括身份验证、访问控制、加密、传输加密以及审计日志等。这些措施共同作用,确保数据的安全性和完整性。MongoDB的主要安全功能包括:
- 身份验证:MongoDB支持多种身份验证机制,如SCRAM和X.509证书身份验证,用于用户凭据的验证。
- 访问控制:基于角色的访问控制(Role-Based AccessControl,RBAC),为不同用户和应用程序分配不同的访问权限。
- 加密:支持数据传输加密和存储加密,使用SSL/TLS协议对数据传输进行加密,并使用加密算法对数据存储进行加密。
- 传输加密:通过TLS/SSL协议配置加密mongod、mongos、应用程序和MongoDB之间的通信通道,确保数据传输的安全。
- 审计日志:记录所有的数据库操作,包括谁对数据库进行了哪些操作,帮助管理员监控数据库的访问和操作情况。
常见的MongoDB安全威胁主要有以下几方面。
- 未经授权的访问:未经授权的用户或应用程序可能会访问MongoDB数据库,导致数据泄露或篡改。
- 数据库泄露:配置不当或存在漏洞,可能会导致数据库内容泄露给未经授权的第三方。
- 拒绝服务攻击(Distributed Denial of Service,DDoS):恶意用户可能会发起拒绝服务攻击,导致数据库无法正常响应请求,影响业务正常运行。
- 数据篡改:恶意用户可能会篡改数据库中的数据,破坏数据的完整性。
2、基于SCRAM的身份验证
2.1、SCRAM机制
MongoDB数据库中的Salted质询响应身份验证机制(Salted Challenge Response AuthenticationMechanism,SCRAM)是MongoDB默认的身份验证机制。当用户进行身份验证时,MongoDB会使用SCRAM针对用户的name、password和authenticationdatabase来验证所提供的用户凭证。
SCRAM基于IETF RFC 5802标准,该标准定义了实现质询响应机制以使用密码对用户进行身份验证的最佳实践。MongoDB的SCRAM实现提供了以下功能:
- 可调工作因子(迭代计数)。
- 每个用户的随机盐。
- 服务器和客户端之间的双向身份验证。
MongoDB数据库支持的SCRAM机制如表所示。

创建或更新SCRAM用户时,可以指定如下内容:
- 要使用的SCRAM机制。
- 对密码进行摘要处理的是服务器还是客户端。
如果使用SCRAM-SHA-256,MongoDB需要服务器端密码哈希,这意味着服务器会对密码进行摘要处理。如果使用SCRAM-SHA-1,MD5是有必要使用的,但并不用于加密目的。如果使用的是FIPS模式,则不使用SCRAM-SHA-1,而是使用SCRAM-SHA-256、Kerberos、LDAP或x.509。
2.2、使用SCRAM对客户端进行身份验证
在独立运行的mongod实例上进行客户端身份验证,设置SCRAM的步骤如下:
步骤1:在没有访问控制的情况下启动MongoDB。
在没有访问控制的情况下,启动独立运行的mongod实例,打开终端并以mongod用户的身份运行以下命令:
bash
mongod --port 27017 --dbpath /var/lib/mongodb
上面代码中使用的端口(port 27017)和数据目录路径(/var/lib/mongodb)只是具体的示例。设计人员可以根据自己的实际项目需求进行指定。
这里补充说明一下,当mongod启动时,会在数据目录路径(/var/lib/mongodb)中创建一些系统文件。为了确保系统文件具有正确的所有权,需要以mongod用户身份登录。如果以root用户身份启动mongod,则必须稍后更新文件所有权。
步骤2:连接到实例。
打开新终端并使用mongosh连接到集群,具体命令如下:
bash
mongosh --port 27017
如要连接到其他部署,可根据需要指定--host等其他命令行选项进行连接。
步骤3:创建用户管理员。
使用mongosh切换到admin数据库,添加具有userAdminAnyDatabase和readWriteAnyDatabase角色的myUserAdmin用户,具体命令如下:
js
use admin
db.createUser({
user: "myUserAdmin",
pwd: passwordPrompt(), //or cleartext password
roles: [
{role: "userAdminAnyDatabase", db: "admin"},
{role: "readWriteAnyDatabase", db: "admin"}
]
})
在上述代码中,passwordPrompt()方法会提示输入密码,在使用时也可以直接将密码指定为字符串。这里建议使用passwordPrompt()方法,可以避免将密码显示在屏幕上,同时避免将密码泄露到Shell历史记录中。
一般情况下,userAdminAnyDatabase角色允许用户进行如下操作:
- 创建用户。
- 授予或撤销用户的角色。
- 创建或修改自定义角色。
另外,可以根据需要为用户分配其他内置角色或用户自定义角色。创建该用户的数据库即为该用户的身份验证数据库。虽然该用户需要通过此数据库进行身份验证,但该用户还可能会在其他数据库中拥有角色。同时,该用户的身份验证数据库不会限制该用户的特权。
步骤4:使用访问控制重新启动MongoDB实例。
关闭mongod实例,使用mongosh发出以下命令:
js
db.adminCommand({ shutdown: 1 })
然后,退出mongosh命令行。
在启用访问控制的情况下启动mongod,如果在命令行中启动mongod,则需要添加--auth命令行选项:
bash
mongod --auth --port 27017 --dbpath /var/lib/mongodb
如果使用配置文件启动mongod,则添加以下security.authorization配置文件设置:

连接到此实例的客户端现在必须对自身进行身份验证,并且只能执行由所分配角色确定的操作。
步骤5:连接并认证为用户管理员。
使用mongosh即可进行身份验证,包括在连接期间进行身份验证和在连接后进行身份验证两种情形。
- 在连接期间进行身份验证
使用-u <username>、-p和--authenticationDatabase<database>命令行选项启动mongosh,具体命令如下:
bash
mongosh --port 27017 --authenticationDatabase "admin" -u "myUserAdmin" -p
然后,根据提示输入密码。
- 在连接后进行身份验证
使用mongosh连接到数据库部署:
bash
mongosh --port 27017
在mongosh中,切换到身份验证数据库,并使用db.auth(<username>, <pwd>)方法进行身份验证:
js
use admin
db.auth("myUserAdmin", passwordPrompt()) // or cleartext password
然后,根据提示输入密码。
3、基于x.509的身份验证
3.1、x.509机制
MongoDB数据库支持将x.509证书用于客户端身份验证,以及副本集和分片集群成员的内部身份验证,使用x.509证书进行身份验证需要安全的TLS/SSL连接。
MongoDB对于生产用途的部署,要求使用由证书颁发机构生成和签名的有效证书。对于客户端x.509证书,要对服务器进行身份验证,客户端可以使用x.509证书来替代用户名和密码。
关于x.509客户端证书的具体要求说明如下:
- 必须由一个证书颁发机构(Certificate Authority,CA)同时向客户端和服务器颁发证书。
- 每个唯一的MongoDB用户必须拥有唯一的证书。
- x.509证书不能过期。如果显示的x.509证书在mongod/mongos主机系统时间后的30天内过期,则mongod/mongos会在连接时记录警告。
- 客户端证书必须包含以下字段:
以下客户端证书属性中至少有一个必须与net.tls.clusterFile和net.tls.certificateKeyFile服务器证书中的属性不同:- 组织(Organization, O)。
- 组织单位(Organizational Unit, OU)。
- 域控制器(Domain Controller, DC)。
js
keyUsage = digitalSignature
extendedKeyUsage = clientAuth
- 客户端x.509证书的subject包含标识名(DistinguishedName, DN),必须与成员x.509证书的subject不同。如果MongoDB部署设置了tlsX509ClusterAuthDNOverride,则客户端x.509证书的主题不得与该值匹配。
要使用客户端证书进行身份验证,必须先将客户端证书的subject作为MongoDB用户添加到$external数据库中,$external数据库是用户的身份验证数据库。
每个唯一的x.509客户端证书对应一个MongoDB用户,不能使用一个客户端证书验证多个MongoDB用户。要对$external身份验证用户(Kerberos、LDAP或x.509用 户)使用客户端会话和因果一致性保证,用户名不能大于10KB。
3.2、使用x.509对客户端进行身份验证
下面介绍通过设置x.509证书身份验证,用于独立运行mongod实例上的客户端身份验证。这种方法也称为双向TLS或mTLS。关于TLS/SSL、PKI(Public KeyInfrastructure,公钥基础设施)证书(尤其是x.509证书)和证书颁发机构的完整描述已超出本文档的范围。
对于生产用途,MongoDB部署应使用由证书颁发机构生成和签名的有效证书。如果使用x.509身份验证,则必须指定--tlsCAFile或net.tls.CAFile,除非使用--tlsCertificateSelector或--net.tls.certificateSelector。
对于客户端x.509证书,使用时必须拥有有效的x.509证书,客户x.509证书必须符合客户端证书要求。如果指 定--tlsAllowInvalidCertificates或net.tls.allowInvalidCertificates: true,则无效证书仅足以建立TLS连接,但不足以进行身份验证。
在独立运行的mongod实例上进行客户端身份验证设置x.509的步骤,具体内容如下:
步骤1:使用x.509身份验证进行部署。
通过命令行为x.509身份验证配置mongod实例,要配置独立运行的mongod实例,可运行以下命令:

步骤2:添加x.509证书subject作为用户。
要使用客户端证书进行身份验证,必须先以MongoDB用户身份将客户端证书中的subject值添加到$external数据库。每个唯一的x.509客户端证书对应一个MongoDB用户,同时不能使用一个客户端证书验证多个MongoDB用户。
对于用户名有如下要求:
- 要对$external身份验证用户(Kerberos、LDAP或x.509用户)使用客户端会话和因果一致性保证,用户名不能大于10KB。
- subject字符串中的RDN必须与RFC2253标准兼容。
步骤3:使用x.509证书进行身份验证。
将x.509客户端证书主题添加为相应的MongoDB用户后,可以使用该客户端证书进行身份验证,包括使用身份验证进行连接和连接后进行身份验证两种情形。
- 使用身份验证进行连接
要在连接过程中进行身份验证,可运行以下命令:

- 连接后进行身份验证
在连接后使用db.auth()方法进行身份验证。例如,使用mongosh命令连接到mongod:

若要进行身份验证,则需要使用$external数据库中的db.auth()方法,在mechanism字段中指定"MONGODB-X509"。

4、加密
4.1、加密方法
MongoDB数据库提供以下加密方法:
- 正在使用的加密。分别是可查询Queryable Encryption和客户端字段级加密(Client-Side Field LevelEncryption,CSFLE)。选择正在使用的加密方法,可以在同一部署中同时使用可查询加密(QueryableEncryption)和客户端字段级加密,但它们在同一集合中彼此不兼容。
- 静态加密。静态加密与传输加密和保护相关账户、密码和加密密钥的安全策略结合使用。静态加密可以帮助确保符合安全和隐私标准,包括HIPAA、PCI-DSS和FERPA。
- TLS/SSL(传输加密)。MongoDB支持使用TLS/SSL(传输层安全性/安全套接层)加密MongoDB的所有网络 流量。TLS/SSL可确保MongoDB网络流量只能由目标客户端读取。
4.2、选择正在使用的加密方法
MongoDB提供两种"正在使用的加密"方法,分别是可查询加密和客户端字段级加密。使用其中一种方法时,即可在自动加密和显式加密之间进行选择。
可查询加密和客户端字段级加密都允许客户端应用程序在通过网络传输数据之前对其进行加密。敏感数据由客户端透明地加密和解密,并且仅以加密形式与服务器通信。在实施使用可查询加密或客户端字段级加密的应用程序时,需要特别注意以下安全注意事项:
- 客户端字段级加密和可查询加密不提供任何ACID一致性保证,以防止攻击者访问客户主密钥和数据加密密钥。
- 客户端字段级加密和可查询加密不能提供ACID一致性保证,攻击者可以对包含加密数据的集合进行任意写入访问权限。
- MongoDB使用模式验证来实施集合中特定字段的加密。如果没有客户端模式,客户端将下载集合的服务器端模式来确定要加密哪些字段。如果要避免此问题,可使用客户端模式验证。
- 由于CSFLE和Queryable Encryption不提供验证模式完整性的机制,因此依赖服务器端模式意味着相信服务器的模式没有被篡改。如果攻击者破坏了服务器,他们就可以修改模式,使以前加密的字段不再被标记为加密,这会导致客户端发送该字段的明文值。
可查询加密支持对加密字段进行相等和范围查询。对使用可查询加密进行前缀、后缀和子字符串查询的支持正在开发中。客户端字段级加密支持对确定性加密字段进行相等查询。可查询加密的新加密算法使用基于结构化加密的随机加密,可从同一输入生成不同的加密输出值。客户端字段级加密算法同时支持随机加密和确定性加密。但是,它仅支持查询确定性加密的字段。使用确定性加密,给定的输入值始终加密为相同的输出值。
MongoDB对可查询加密和客户端字段级加密的查询进行加密,以便服务器避免有关明文文档或查询值的信息。借助可查询加密,私有查询更进一步,可以编辑日志和元数据以清理有关查询存在的信息,这样可以确保更强的隐私性和机密性。
4.3、静态加密
MongoDB静态加密与传输加密结合使用时,可以保护相关账户、密码和加密密钥的安全策略,从而确保数据库符合安全和隐私标准,包括HIPAA、PCI-DSS和FERPA。
MongoDB Enterprise 3.2为WiredTiger存储引擎引入了一个原生加密选项,此功能允许MongoDB加密数据文件,仅限持有解密密钥的各方可以解码和读取数据。Windows上的MongoDB Enterprise不再支持将AES256-GCM作为静态加密的分组密码算法,仅Linux版本支持此用法。
如果启用加密,MongoDB Enterprise使用的默认加密模式则是通过OpenSSL实现的AES256-CBC(或是采用密码分组链接模式的256位高级加密标准)。AES-256使用对称密钥,即使用同一密钥来加密和解密文本。MongoDB Enterprise for Linux还支持经过身份验证的加密AES256-GCM(或是采用Galois/Counter模式的256位高级加密标准)。
加密存储引擎使用认证的底层操作系统加密提供程序来执行加密操作。例如,在Linux操作系统上安装的MongoDB将使用OpenSSL libcrypto FIPS-140模块。
要在符合FIPS标准的模式下运行MongoDB,需要:
- 将操作系统配置为在FIPS强制模式下运行。
- 配置MongoDB以启用net.tls.FIPSMode设置。
- 重新启动mongod或mongos。
检查服务器日志文件以确认FIPS模式已启用。如果FIPS模式已启用,则日志文件中会显示消息FIPS 140-2 modeactivated。
数据加密流程包括:
步骤1:生成主密钥。
步骤2:为每个数据库生成密钥。
步骤3:用数据库密钥加密数据。
步骤4:使用主密钥来加密数据库密钥。
此加密在存储层以透明方式进行,即从文件系统的角度来看,所有数据文件都是完全加密的,而数据仅以未加密状态存在于内存和传输过程中。如果要加密MongoDB的所有网络流量,可以使用TLS/SSL(传输层安全性/安全套接字层)。
4.4、TLS/SSL
MongoDB支持使用TLS/SSL加密MongoDB的所有网络流量。TLS/SSL可确保MongoDB网络流量只能由目标客户端读取。
1. mongod和mongos证书密钥文件
在建立TLS/SSL连接时,mongod和mongos会向其客户端提交证书密钥文件,以确定其身份。证书密钥文件包含公钥证书及其关联的私钥,但仅向客户端透露公钥部分。MongoDB可以使用自签名证书或证书颁发机构颁发的任何有效TLS证书。如果使用自签名证书,尽管会加密通信通道以防止窃听连接,但不会验证服务器身份。
2.客户端的TLS/SSL配置
客户端必须支持TLS/SSL,才能连接到需要TLS/SSL连接的mongod或mongos实例。关于TLS/SSL、PKI(公钥基础设施)证书和证书颁发机构的完整描述,可以参看官方权威说明。对于TLS/SSL连接,mongosh会验证mongod或mongos实例提供的证书。
3.为FIPS配置MongoDB
FIPS是加密系统的属性,而不是访问权限控制系统的属性。但是,如果环境需要符合FIPS标准的加密和访问权限控制,则必须确保访问权限控制系统仅使用符合FIPS标准的加密。MongoDB的FIPS支持涵盖MongoDB使用SSL/TLS库进行网络加密、SCRAM身份验证和x.509身份验证的方式。如果使用Kerberos或LDAP身份验证,则必须确保这些外部机制与FIPS兼容。