mongodb 6.0 客户端字段级加密(fle)需 libmongocrypt 1.6+ 及支持驱动,依赖 kms 或本地 96 字节主密钥生成 data key 并存于 __keyvault;加密字段须在 collection 级 json schema 中声明,仅 deterministic 算法支持等值查询,驱动自动加解密且禁止明文操作。

客户端字段级加密(FLE)在 MongoDB 6.0 中必须用 libmongocrypt 1.6+ 和支持 FLE 的驱动
MongoDB 6.0 原生支持客户端字段级加密,但不是开箱即用——它依赖驱动层的 libmongocrypt 库完成密钥管理与加解密逻辑。如果你用的是 Python(pymongo 4.0+)、Node.js(mongodb 4.13+)或 Java(4.9+),得确认驱动版本背后绑定的 libmongocrypt ≥ 1.6;否则 AutoEncryptionOpts 初始化会静默失败或抛出 EncryptionException: libmongocrypt not found。
常见踩坑点:
- macOS 上通过
pip install pymongo安装的预编译 wheel 可能不含libmongocrypt动态库,需改用pip install pymongo --no-binary :all:强制源码编译 - Linux 容器中若未安装
libmongocrypt-dev(Debian/Ubuntu)或libmongocrypt-devel(RHEL/CentOS),构建时会跳过加密模块 - Node.js 驱动默认不启用 FLE,必须显式传入
autoEncryption配置对象,且kmsProviders字段不能为空(哪怕只用本地密钥)
密钥必须由 KMS 或本地 master key 生成,不能手写或硬编码 data key
FLE 要求每个加密字段对应一个 data key 文档,该文档本身用 master key 加密后存于 __keyVault 集合。master key 可来自 AWS KMS、Azure Key Vault、GCP KMS,或本地 96 字节随机密钥(仅限开发)。你不能手动构造 dataKeyId 或把密钥明文塞进代码里。
正确做法:
- 用驱动提供的
createDataKey方法生成 data key,并指定kmsProvider名称(如"local"或"aws") - 本地 master key 必须是 96 字节 Buffer(Node.js)或 bytes(Python),格式错误会导致
Invalid argument: localMasterKey must be exactly 96 bytes - AWS KMS 需提前创建 CMK 并赋予执行角色
kms:Decrypt和kms:GenerateDataKey权限,否则连接时就报KMS request failed: AccessDeniedException
示例(Python):
from pymongo import MongoClient
from pymongo.encryption import ClientEncryption
import os
<p>key_vault_namespace = "encryption.__keyVault"
kms_providers = {
"local": {
"key": os.urandom(96) # 开发环境用,生产必须换 KMS
}
}</p><p>client_enc = ClientEncryption(
kms_providers,
key_vault_namespace,
MongoClient("mongodb://localhost:27017"),
CodecOptions()
)
data_key_id = client_enc.create_data_key("local") # 返回 ObjectId,用于 schema</p>
JSON Schema 必须放在 collection level,且只对指定字段启用加密
MongoDB 不允许在插入时动态决定是否加密——所有加密行为由服务端自动触发,前提是 collection 已关联一个含 encrypt 规则的 JSON Schema,并通过 createCollection 显式设置。如果只在应用层调用 encrypt() 手动加,那就不叫 FLE,而是手动加密,无法享受查询能力(如范围查询、等值匹配)。
关键约束:
- schema 必须包含
"bsonType": "object"根节点,且每个要加密字段需声明"encrypt"子对象 -
"algorithm"只能是"AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"(支持等值查询)或"AEAD_AES_256_CBC_HMAC_SHA_512-Random"(更高安全,不支持查询) - collection 创建后不能修改 schema 中的
encrypt配置;改 schema 需重建 collection + 迁移数据 - 服务端必须开启
enableMongoCryptd(6.0 默认开启),否则带加密 schema 的 collection 创建会失败并提示Failed to create collection: Encryption is not enabled
查询加密字段时,必须用原始值(非密文),且驱动自动处理加解密
这是最容易误解的一点:你写 db.users.find({"ssn": "123-45-6789"}),驱动会在发送前把 "123-45-6789" 按对应 data key 和 algorithm 加密成二进制 blob,再发给服务器;返回结果中该字段也会被自动解密。你永远不需要接触密文。
但要注意:
- 只有 deterministic 加密字段支持等值查询;random 加密字段只能查
{ssn: {$exists: true}}这类操作 - 使用聚合管道时,
$match阶段可以查加密字段,但$group、$sort等不能基于加密字段做计算——服务端不知道明文 - 如果查询字段没在 schema 里声明加密,或 data key 被删/失效,查询仍能跑通,但返回的是密文二进制(
BinData(6, "...")),不是明文 - 启用 FLE 后,所有对加密字段的写操作都会被拦截并加密;但如果绕过 driver 直接用 mongosh 或其他工具插入,字段就是明文,破坏安全性
真正麻烦的地方在于密钥轮换和跨服务共享 keyVault:一旦多个应用共用同一个 __keyVault,就必须统一 KMS 权限模型和 data key 生命周期管理——这里出错,整个加密链就断了。











