文档菜单
文档首页
/
MongoDB 手册
/ / / / /

显式加密

在本页面上

  • 概述
  • 使用显式加密
  • 创建 ClientEncryption 实例
  • 在读写操作中加密字段
  • 手动解密
  • 自动解密
  • 示例
  • 创建 MongoClient 实例
  • 创建 ClientEncryption 实例
  • 加密字段并插入
  • 检索文档并解密字段
  • 服务器端字段级加密强制执行
  • 了解更多

显式加密提供了对安全性的精细控制,但需要在配置集合和为MongoDB驱动程序编写代码时承担增加的复杂性。使用显式加密时,您需要指定如何对数据库中每个操作执行的文档字段进行加密,并在您的整个应用程序中包含此逻辑。

以下MongoDB产品支持显式加密

  • MongoDB社区服务器

  • MongoDB企业高级版

  • MongoDB Atlas

要在您的CSFLE启用应用程序中使用显式加密,您必须执行以下操作

  • 创建 ClientEncryption 实例

  • 在读写操作中加密字段

  • 手动自动解密您的文档中的字段

要使用显式加密,您必须创建一个ClientEncryption实例。ClientEncryption是跨驱动程序和mongosh使用的抽象,用于封装显式加密所涉及的密钥库集合和KMS操作。

要创建ClientEncryption实例,您必须指定以下信息

  • 一个具有访问您的密钥库集合的 MongoClient 实例

  • 您的密钥库集合的命名空间

  • 一个配置了访问托管您的客户主密钥的 KMS 提供程序的 kmsProviders 对象

有关更多 ClientEncryption 选项,请参阅CSFLE 的 MongoClient 选项.

要查看创建 ClientEncryption 实例的代码片段,请参阅本指南的 示例 部分。

您必须更新应用程序中的读写操作,以便在执行读写操作之前加密字段。

要加密字段,请使用您的 ClientEncryption 实例的 encrypt 方法。

要查看如何使用 encrypt 方法的代码片段,请参阅本指南的 示例 部分。

当使用显式加密时,您可以手动或自动解密加密字段。

要手动解密字段,请使用您的 ClientEncryption 实例的 decrypt 方法。

要查看如何使用 decrypt 方法的代码片段,请参阅本指南的 示例 部分。

要自动解密您的字段,请按以下方式配置您的 MongoClient 实例

  • 指定您的密钥保管库集合

  • 指定一个 kmsProviders 对象

  • 如果您使用 MongoDB Community Server,将 bypassAutoEncryption 选项设置为 True

注意

自动解密在 MongoDB Community Server 中可用

尽管自动加密需要 MongoDB Enterprise 或 MongoDB Atlas,但自动解密在以下 MongoDB 产品中可用

  • MongoDB社区服务器

  • MongoDB企业高级版

  • MongoDB Atlas

要查看如何启用自动解密的代码片段,请选择您首选语言的选项卡

var autoEncryptionOpts = {
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders,
bypassAutoEncryption: true,
};
var encryptedClient = Mongo(
connectionString,
autoEncryptionOpts
);
var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
var autoEncryptionOptions = new AutoEncryptionOptions(
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders,
bypassAutoEncryption: true);
clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
var client = new MongoClient(clientSettings);
autoEncryptionOpts := options.AutoEncryption().
SetKmsProviders(kmsProviders).
SetKeyVaultNamespace(KeyVaultNamespace).
SetBypassAutoEncryption(true)
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(URI).SetAutoEncryptionOptions(autoEncryptionOpts))
if err != nil {
return fmt.Errorf("Connect error for encrypted client: %v", err)
}
defer func() {
_ = client.Disconnect(context.TODO())
}()
MongoClientSettings clientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.autoEncryptionSettings(AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders).bypassAutoEncryption(true)
.build())
.build();
MongoClient mongoClient = MongoClients.create(clientSettings);
const client = new MongoClient(connectionString, {
monitorCommands: true,
autoEncryption: {
keyVaultNamespace,
kmsProviders,
bypassAutoEncryption: true,
},
});
auto_encryption_opts = AutoEncryptionOpts(
kms_providers=kms_providers,
key_vault_namespace=key_vault_namespace,
bypass_auto_encryption=True,
)
client = MongoClient(auto_encryption_opts=auto_encryption_opts)

假设您想将以下结构的文档插入到您的 MongoDB 实例中

{
"name": "<name of person>",
"age": <age of person>,
"favorite-foods": ["<array of foods>"]
}
1

在这个例子中,您使用相同的 MongoClient 实例来访问您的密钥保管库集合以及读取和写入加密数据。

以下代码片段展示了如何创建一个 MongoClient 实例

const autoEncryptionOpts = {
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders,
};
const encryptedClient = Mongo(connectionString, autoEncryptionOpts);
var client = new MongoClient(connectionString);
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(URI))
if err != nil {
panic(fmt.Errorf("Client connect error %v", err))
}
MongoClient client = MongoClients.create(connectionString);
const client = new MongoClient(connectionString);
client = MongoClient(your_connection_uri)
2

以下代码片段展示了如何创建一个 ClientEncryption 实例

const clientEncryption = encryptedClient.getClientEncryption();
var collection = client.GetDatabase(db).GetCollection<BsonDocument>(coll);
var clientEncryptionOptions = new ClientEncryptionOptions(
keyVaultClient: client,
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders);
var clientEncryption = new ClientEncryption(clientEncryptionOptions);
coll := client.Database(DbName).Collection(CollName)
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(KeyVaultNamespace).SetKmsProviders(kmsProviders)
clientEnc, err := mongo.NewClientEncryption(client, clientEncryptionOpts)
if err != nil {
panic(fmt.Errorf("NewClientEncryption error %v", err))
}
defer func() {
_ = clientEnc.Close(context.TODO())
}()
MongoCollection<Document> collection = client.getDatabase(db).getCollection(coll);
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.build())
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.build();
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
const collection = client.db(db).collection(coll);
const encryption = new ClientEncryption(client, {
keyVaultNamespace,
kmsProviders,
});
coll = client.employees.foods
client_encryption = ClientEncryption(
kms_providers,
"encryption.___keyVault",
client,
coll.codec_options,
)

注意

CodecOptions

MongoDB Python 驱动程序要求您指定用于加密和解密文档的 CodecOptions

指定您在 MongoClientDatabaseCollection 上配置的 CodecOptions,您将通过它将加密和解密的应用程序数据写入 MongoDB。

3

您想使用以下算法加密文档的字段

字段名称
加密算法
字段 BSON 类型
name
确定性
字符串
age
无加密
Int
favorite-foods
随机
数组

以下代码片段展示了如何手动加密文档中的字段并将文档插入到 MongoDB 中

注意

以下示例中的 dataKeyId 变量指的是数据加密密钥 (DEK)。要了解如何使用本地密钥提供程序生成 DEK,请参阅 快速入门。要了解如何使用特定的密钥管理系统创建 DEK,请参阅 教程

const encName = clientEncryption.encrypt(
dataKeyId,
"Greg",
"AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
);
const encFoods = clientEncryption.encrypt(
dataKeyId,
["Cheese", "Grapes"],
"AEAD_AES_256_CBC_HMAC_SHA_512-Random"
);
db.getSiblingDB(database).getCollection(collection).insertOne({
name: encName,
foods: encFoods,
});

注意

以下示例中的 dataKeyId 变量指的是数据加密密钥 (DEK)。要了解如何使用本地密钥提供程序生成 DEK,请参阅 快速入门。要了解如何使用特定的密钥管理系统创建 DEK,请参阅 教程

var encryptedName = clientEncryption.Encrypt(
"Greg",
new EncryptOptions(algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", keyId: dataKeyId),
CancellationToken.None);
var encryptedFoods = clientEncryption.Encrypt(
new BsonArray { "Cheese", "Grapes" },
new EncryptOptions(algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random", keyId: dataKeyId),
CancellationToken.None);
collection.InsertOne(new BsonDocument { { "name", encryptedName }, { "age", 83 }, { "foods", encryptedFoods } });

注意

以下示例中的 dataKeyId 变量指的是数据加密密钥 (DEK)。要了解如何使用本地密钥提供程序生成 DEK,请参阅 快速入门。要了解如何使用特定的密钥管理系统创建 DEK,请参阅 教程

nameRawValueType, nameRawValueData, err := bson.MarshalValue("Greg")
if err != nil {
panic(err)
}
nameRawValue := bson.RawValue{Type: nameRawValueType, Value: nameRawValueData}
nameEncryptionOpts := options.Encrypt().
SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").
SetKeyID(dataKeyId)
nameEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
nameRawValue,
nameEncryptionOpts)
if err != nil {
panic(err)
}
foodsRawValueType, foodsRawValueData, err := bson.MarshalValue(bson.A{"Grapes", "Cheese"})
if err != nil {
panic(err)
}
foodsRawValue := bson.RawValue{Type: foodsRawValueType, Value: foodsRawValueData}
encryptionOpts := options.Encrypt().
SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Random").
SetKeyID(dataKeyId)
foodsEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
foodsRawValue,
encryptionOpts)
if err != nil {
panic(err)
}
_, err = coll.InsertOne(
context.TODO(),
bson.D{{"name", nameEncryptedField}, {"foods", foodsEncryptedField}, {"age", 83}})
if err != nil {
panic(err)
}

注意

以下示例中的 dataKeyId 变量指的是数据加密密钥 (DEK)。要了解如何使用本地密钥提供程序生成 DEK,请参阅 快速入门。要了解如何使用特定的密钥管理系统创建 DEK,请参阅 教程

BsonBinary encryptedName = clientEncryption.encrypt(new BsonString("Greg"), new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId));
BsonBinary encryptedFoods = clientEncryption.encrypt(new BsonArray().parse("[\"Grapes\", \"Foods\"]"), new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Random").keyId(dataKeyId));
collection.insertOne(new Document("name", encryptedName).append("foods", encryptedFoods).append("age", 83));

注意

以下示例中的 dataKeyId 变量指的是数据加密密钥 (DEK)。要了解如何使用本地密钥提供程序生成 DEK,请参阅 快速入门。要了解如何使用特定的密钥管理系统创建 DEK,请参阅 教程

encryptedName = await encryption.encrypt("Greg", {
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
keyId: dataKeyId,
});
encryptedFoods = await encryption.encrypt(["Cheese", "Grapes"], {
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
keyId: dataKeyId,
});
await collection.insertOne({
name: encryptedName,
age: 83,
foods: encryptedFoods,
});

注意

以下示例中的 data_key_id 变量指的是数据加密密钥(DEK)。要了解如何使用本地密钥提供程序生成 DEK,请参阅快速入门。要了解如何使用特定的密钥管理系统创建 DEK,请参阅教程

encrypted_name = client_encryption.encrypt(
"Greg",
Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic,
key_id=data_key_id,
)
encrypted_foods = client_encryption.encrypt(
["Cheese", "Grapes"],
Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
key_id=data_key_id,
)
coll.insert_one({"name": encrypted_name, "age": 83, "foods": encrypted_foods})
4

以下代码片段展示了如何检索插入的文档并手动解密加密字段。

const encNameQuery = clientEncryption.encrypt(
dataKeyId,
"Greg",
"AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
);
let doc = db.getSiblingDB(database).getCollection(collection).findOne({
name: encNameQuery,
});
console.log(doc);
doc.name = clientEncryption.decrypt(doc.name);
doc.foods = clientEncryption.decrypt(doc.foods);
console.log(doc);
var nameToQuery = "Greg";
var encryptedNameToQuery = clientEncryption.Encrypt(
nameToQuery,
new EncryptOptions(algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", keyId: dataKeyId),
CancellationToken.None);
var doc = collection.Find(new BsonDocument { { "name", encryptedNameToQuery } }).Single();
Console.WriteLine($"Encrypted document: {doc}");
doc["name"] = clientEncryption.Decrypt(doc["name"].AsBsonBinaryData, CancellationToken.None);
doc["foods"] = clientEncryption.Decrypt(doc["foods"].AsBsonBinaryData, CancellationToken.None);
Console.WriteLine($"Decrypted field: {doc}");
nameQueryRawValueType, nameQueryRawValueData, err := bson.MarshalValue("Greg")
if err != nil {
panic(err)
}
nameQueryRawValue := bson.RawValue{Type: nameQueryRawValueType, Value: nameQueryRawValueData}
nameQueryEncryptionOpts := options.Encrypt().
SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").
SetKeyID(dataKeyId)
nameQueryEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
nameQueryRawValue,
nameQueryEncryptionOpts)
if err != nil {
panic(err)
}
var result bson.M
err = coll.FindOne(
context.TODO(),
bson.D{{"name", nameQueryEncryptedField}}).Decode(&result)
if err != nil {
if err == mongo.ErrNoDocuments {
return
}
panic(err)
}
fmt.Printf("Encrypted Document: %s\n", result)
nameDecrypted, err := clientEnc.Decrypt(
context.TODO(),
result["name"].(primitive.Binary))
foodsDecrypted, err := clientEnc.Decrypt(
context.TODO(),
result["foods"].(primitive.Binary))
result["foods"] = foodsDecrypted
result["name"] = nameDecrypted
fmt.Printf("Decrypted Document: %s\n", result)
BsonBinary encryptedNameQuery = clientEncryption.encrypt(new BsonString("Greg"), new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId));
Document result = collection.find(eq("name", encryptedNameQuery)).first();
System.out.println("Encrypted Document: " + result.toJson());
result.replace("name", clientEncryption.decrypt(new BsonBinary(result.get("name", Binary.class).getData())));
result.replace("foods", clientEncryption.decrypt(new BsonBinary(result.get("foods", Binary.class).getData())));
System.out.println("Decrypted Document: " + result.toJson());
queryEncryptedName = await encryption.encrypt("Greg", {
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
keyId: dataKeyId,
});
let doc = await collection.findOne({ name: queryEncryptedName });
console.log("Encrypted Document: ", doc);
doc.name = encryption.decrypt(doc.name);
doc.foods = encryption.decrypt(doc.foods);
console.log("Decrypted document: ", doc);
name_to_query = "Greg"
encrypted_name_to_query = client_encryption.encrypt(
name_to_query,
Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic,
key_id=data_key_id,
)
doc = client.employees.foods.find_one({"name": encrypted_name_to_query})
print("Encrypted document: %s" % (doc,))
doc["name"] = client_encryption.decrypt(doc["name"])
doc["foods"] = client_encryption.decrypt(doc["foods"])
print("Decrypted document: %s" % (doc,))

MongoDB 支持使用 模式验证 来强制执行集合中特定字段的加密。

在配置为强制执行某些字段加密的 MongoDB 实例上执行客户端字段级加密的客户必须按照 MongoDB 实例上指定的方式加密这些字段。

要了解如何设置服务器端 CSFLE 强制执行,请参阅CSFLE 服务器端模式强制执行

要了解更多关于密钥保管库集合、数据加密密钥和客户主密钥的信息,请参阅加密密钥和密钥保管库。

要了解更多关于 KMS 提供者和 kmsProviders 对象的信息,请参阅KMS 提供者。

返回

自动加密

© . All rights reserved.