Queryable Encryption 是 MongoDB 客户端字段级加密方案,仅加密显式标记的 BSON 基本类型字段(如 ssn、creditCardNumber),支持 deterministic(等值查询)和 random(范围/存在性查询)两种模式,密钥由客户端持有,服务端仅存储密文。

Queryable Encryption 是什么,它能加密哪些字段
Queryable Encryption 不是数据库整体加密方案,也不是对整个集合或文档做透明加解密。它只作用于你明确标记的字段,比如 ssn、creditCardNumber、patientId,且这些字段必须是 BSON 基本类型(string、int、date 等),不能是嵌套对象或数组。
它支持两种加密模式:deteterministic(确定性加密)和 random(随机加密)。前者允许等值查询(如 { ssn: "123-45-6789" }),后者仅支持范围/存在性查询(需配合索引和客户端驱动解密逻辑),但安全性更高。
注意:加密字段在服务端始终以密文形式存在,MongoDB 服务进程本身无法解密——密钥由客户端持有,解密发生在驱动层。
如何配置 Client-Side Field Level Encryption(CSFLE)
启用 Queryable Encryption 需要三步准备,缺一不可:
- 在 MongoDB 部署中启用
enableEncryption 并配置 KMS(如 AWS KMS、Azure Key Vault 或本地 local 密钥)
- 使用
mongocryptd(或 6.0+ 内置的 mongod 加密子系统)提供元数据加密支持
- 在应用代码中通过驱动配置
autoEncryption 选项,并传入 keyVaultNamespace 和 kmsProviders
enableEncryption 并配置 KMS(如 AWS KMS、Azure Key Vault 或本地 local 密钥)mongocryptd(或 6.0+ 内置的 mongod 加密子系统)提供元数据加密支持autoEncryption 选项,并传入 keyVaultNamespace 和 kmsProviders
常见错误是跳过 mongocryptd 启动(旧版必需)或误配 kmsProviders 格式——例如 AWS 提供商必须包含 accessKeyId、secretAccessKey 和 sessionToken(若使用临时凭证),漏掉任一字段会导致 AutoEncryptionError: failed to create data key。
如何定义加密字段规则(encryptionSchema)
加密规则不是写在集合上,而是通过客户端驱动注册的 JSON Schema,指定哪些字段走哪种加密方式。例如:
{
"medicalRecords": {
"bsonType": "object",
"properties": {
"patientSsn": {
"encrypt": {
"keyId": [ { "$binary": { "base64": "...", "subType": "04" } } ],
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
},
"diagnosisNotes": {
"encrypt": {
"keyId": [ { "$binary": { "base64": "...", "subType": "04" } } ],
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
}
}
}
}
关键点:
-
keyId必须指向keyVaultNamespace中已存在的密钥文档(通常用client.createDataKey()创建) - 字段名必须与应用写入时的字段名完全一致(区分大小写、无空格)
- 不能对
_id字段加密;也不能对用于分片键、唯一索引的字段使用random加密
查询加密字段时为什么查不到结果
最常踩的坑是混淆了「加密写入」和「加密查询」两个动作。即使字段已按规则加密写入,如果查询时没用客户端驱动的加密能力,而是直连 mongosh 或 Robo 3T 发起查询,服务端只会匹配密文——而密文是随机字节流,人类不可读,自然查不到。
正确做法:
- 所有涉及加密字段的
find、findOne、updateOne必须通过支持 CSFLE 的驱动发起(Node.js 4.14+、Python 4.5+、Java 4.11+) - 查询条件中的加密字段值,必须由驱动自动加密后再发往服务端(不需要手动调用
encrypt()) - 若使用
deteterministic加密,可建普通索引加速查询;若用random,则只能靠客户端解密后过滤,性能开销明显上升
加密字段的调试成本高,密钥轮换、KMS 权限变更、驱动版本不匹配都可能导致静默失败——建议在测试环境先用 local KMS 模拟全流程,再切真实 KMS。











