使用显式加密
在此页面上
概述
本指南向您展示如何使用显式加密和 MongoDB 驱动程序来加密文档。
完成本指南后,您应该能够配置驱动程序,使用显式加密对文档中的字段进行加密。 有了这些知识,您应该能够创建使用显式加密的客户端应用程序。具有自动解密功能。
重要
请勿在生产环境中使用此示例应用程序
本教程中的操作说明包括在不安全的环境中存储加密密钥,因此您不应在生产环境中使用此应用程序的未修改版本。在生产环境中使用此应用程序存在以下风险:未经授权访问加密密钥或丢失解密数据所需的密钥。本教程旨在演示如何使用 Queryable Encryption,而无需设置密钥管理系统。
您可以使用密钥管理系统将加密密钥安全地存储在生产环境中。 KMS是一种远程服务,可安全地存储和管理加密密钥。 要了解如何设置使用KMS且启用了 Queryable Encryption 的应用程序,请参阅Queryable Encryption 教程。
开始之前
要完成并运行本指南中的代码,您需要按照安装要求页面中的步骤来设置开发环境。
提示
请参阅:完整应用程序
要查看您在本指南中创建的应用程序的完整代码,请选择与您的首选 MongoDB 驱动程序对应的标签页,然后点击提供的链接:
步骤
创建客户主密钥
您必须创建客户主密钥 (CMK) 才能执行 Queryable Encryption。
创建 96 字节的客户主密钥并将其保存到文件 master-key.txt
中:
using (var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create()) { var bytes = new byte[96]; randomNumberGenerator.GetBytes(bytes); var localMasterKeyBase64Write = Convert.ToBase64String(bytes); File.WriteAllText("master-key.txt", localMasterKeyBase64Write); }
func localMasterKey() []byte { key := make([]byte, 96) if _, err := rand.Read(key); err != nil { log.Fatalf("Unable to create a random 96 byte data key: %v", err) } if err := ioutil.WriteFile("master-key.txt", key, 0644); err != nil { log.Fatalf("Unable to write key to file: %v", err) } return key }
byte[] localMasterKeyWrite = new byte[96]; new SecureRandom().nextBytes(localMasterKeyWrite); try (FileOutputStream stream = new FileOutputStream("master-key.txt")) { stream.write(localMasterKeyWrite); }
const fs = require("fs"); const crypto = require("crypto"); try { fs.writeFileSync("master-key.txt", crypto.randomBytes(96)); } catch (err) { console.error(err); }
path = "master-key.txt" file_bytes = os.urandom(96) with open(path, "wb") as f: f.write(file_bytes)
警告
请勿在生产环境中使用本地密钥文件
提示
从命令行生成 CMK
使用以下命令从 Unix Shell 或 PowerShell 生成 CMK :
Unix shell:
echo $(head -c 96 /dev/urandom | base64 | tr -d '\n') PowerShell:
$r=[byte[]]::new(64);$g=[System.Security.Cryptography.RandomNumberGenerator]::Create();$g.GetBytes($r);[Convert]::ToBase64String($r)
将上述命令的输出保存到名为 customer-master-key.txt
的文件中。
提示
请参阅:完整代码
要查看制作客户主密钥的完整代码,请参阅 可查询加密示例应用程序存储库。
要查看制作客户主密钥的完整代码,请参阅 可查询加密示例应用程序存储库。
要查看制作客户主密钥的完整代码,请参阅 可查询加密示例应用程序存储库。
要查看制作客户主密钥的完整代码,请参阅 可查询加密示例应用程序存储库。
要查看制作客户主密钥的完整代码,请参阅 可查询加密示例应用程序存储库。
在密钥保管库集合上创建唯一索引
在 encryption.__keyVault
命名空间中的 keyAltNames
字段上创建唯一索引。
选择与所需的 MongoDB 驱动程序对应的标签页:
var connectionString = "<Your MongoDB URI>"; var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); var keyVaultClient = new MongoClient(connectionString); var indexOptions = new CreateIndexOptions<BsonDocument> { Unique = true, PartialFilterExpression = new BsonDocument {{"keyAltNames", new BsonDocument {{"$exists", new BsonBoolean(true)}}}} }; var builder = Builders<BsonDocument>.IndexKeys; var indexKeysDocument = builder.Ascending("keyAltNames"); var indexModel = new CreateIndexModel<BsonDocument>(indexKeysDocument, indexOptions); var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName); // Drop the Key Vault Collection in case you created this collection // in a previous run of this application. keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName); var keyVaultCollection = keyVaultDatabase.GetCollection<BsonDocument>(keyVaultNamespace.CollectionName); keyVaultCollection.Indexes.CreateOne(indexModel);
重要
使用go build
或go run
构建或运行本指南中的 Golang 代码时,请始终包含cse
构建约束以启用可查询加密。有关包含构建约束的示例,请参阅以下 Shell 命令:
go run -tags cse make-data-key.go
uri := "<Your MongoDB URI>" keyVaultClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)) if err != nil { return fmt.Errorf("Connect error for regular client: %v", err) } defer func() { _ = keyVaultClient.Disconnect(context.TODO()) }() keyVaultDb := "encryption" keyVaultColl := "__keyVault" keyVaultNamespace := keyVaultDb + "." + keyVaultColl keyVaultIndex := mongo.IndexModel{ Keys: bson.D{{"keyAltNames", 1}}, Options: options.Index(). SetUnique(true). SetPartialFilterExpression(bson.D{ {"keyAltNames", bson.D{ {"$exists", true}, }}, }), } // Drop the Key Vault Collection in case you created this collection // in a previous run of this application. if err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Drop(context.TODO()); err != nil { log.Fatalf("Collection.Drop error: %v", err) } _, err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Indexes().CreateOne(context.TODO(), keyVaultIndex) if err != nil { panic(err) }
String keyVaultDb = "encryption"; String keyVaultColl = "__keyVault"; MongoClient keyVaultClient = MongoClients.create(connectionString); String encryptedDbName = "medicalRecords"; String encryptedCollName = "patients"; // Drop the Key Vault Collection in case you created this collection // in a previous run of this application. keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl).drop(); MongoCollection keyVaultCollection = keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl); IndexOptions indexOpts = new IndexOptions().partialFilterExpression(new BsonDocument("keyAltNames", new BsonDocument("$exists", new BsonBoolean(true) ))).unique(true); keyVaultCollection.createIndex(new BsonDocument("keyAltNames", new BsonInt32(1)), indexOpts); keyVaultClient.close();
const uri = "<Your Connection String>"; const keyVaultClient = new MongoClient(uri); await keyVaultClient.connect(); const keyVaultDB = keyVaultClient.db(keyVaultDatabase); // Drop the Key Vault Collection in case you created this collection // in a previous run of this application. await keyVaultDB.dropDatabase(); const keyVaultColl = keyVaultDB.collection(keyVaultCollection); await keyVaultColl.createIndex( { keyAltNames: 1 }, { unique: true, partialFilterExpression: { keyAltNames: { $exists: true } }, } );
connection_string = "<your connection string here>" key_vault_coll = "__keyVault" key_vault_db = "encryption" key_vault_namespace = f"{key_vault_db}.{key_vault_coll}" key_vault_client = MongoClient(connection_string) # Drop the Key Vault Collection in case you created this collection # in a previous run of this application. key_vault_client.drop_database(key_vault_db) key_vault_client[key_vault_db][key_vault_coll].create_index( [("keyAltNames", ASCENDING)], unique=True, partialFilterExpression={"keyAltNames": {"$exists": True}}, )
创建你的数据加密密钥和加密collection
读取客户主密钥并指定 KMS 提供商设置
检索您在本指南的创建客户主密钥步骤中生成的客户主密钥文件的内容。
将客户主密钥值传递到您的 KMS 提供商设置。The client uses these settings to discover the CMK. 将提供程序名称设置为local
以通知驱动程序您正在使用本地密钥提供程序。
选择与所需的 MongoDB 驱动程序对应的标签页:
var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>(); const string provider = "local"; var localMasterKeyBase64Read = File.ReadAllText("master-key.txt"); var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read); var localOptions = new Dictionary<string, object> { {"key", localMasterKeyBytes} }; kmsProviders.Add(provider, localOptions);
key, err := ioutil.ReadFile("master-key.txt") if err != nil { log.Fatalf("Could not read the key from master-key.txt: %v", err) } provider := "local" kmsProviders := map[string]map[string]interface{}{"local": {"key": key}}
String kmsProvider = "local"; String path = "master-key.txt"; byte[] localMasterKeyRead = new byte[96]; try (FileInputStream fis = new FileInputStream(path)) { if (fis.read(localMasterKeyRead) < 96) throw new Exception("Expected to read 96 bytes from file"); } Map<String, Object> keyMap = new HashMap<String, Object>(); keyMap.put("key", localMasterKeyRead); Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>(); kmsProviders.put("local", keyMap);
const provider = "local"; const path = "./master-key.txt"; // WARNING: Do not use a local key file in a production application const localMasterKey = fs.readFileSync(path); const kmsProviders = { local: { key: localMasterKey, }, };
provider = "local" path = "./master-key.txt" # WARNING: Do not use a local key file in a production application with open(path, "rb") as f: local_master_key = f.read() kms_providers = { "local": { "key": local_master_key # local_master_key variable from the previous step }, }
创建数据加密密钥
使用 MongoDB 连接字符串和密钥保管库集合命名空间构建客户端,并创建数据加密密钥:
注意
密钥保管库集合命名空间权限
要完成本教程,您的应用程序用于连接到 MongoDB 的数据库用户必须具有对以下命名空间的dbAdmin
权限:
encryption.__keyVault
medicalRecords
数据库
var clientEncryptionOptions = new ClientEncryptionOptions( keyVaultClient, keyVaultNamespace, kmsProviders: kmsProviders ); var clientEncryption = new ClientEncryption(clientEncryptionOptions); var dataKeyOptions1 = new DataKeyOptions(alternateKeyNames: new List<string> { "dataKey1" }); var dataKeyOptions2 = new DataKeyOptions(alternateKeyNames: new List<string> { "dataKey2" }); BsonBinaryData CreateKeyGetID(DataKeyOptions options) { var dateKeyGuid = clientEncryption.CreateDataKey(provider, options, CancellationToken.None); return new BsonBinaryData(dateKeyGuid, GuidRepresentation.Standard); } var dataKeyId1 = CreateKeyGetID(dataKeyOptions1); var dataKeyId2 = CreateKeyGetID(dataKeyOptions2); var dataKeyId3 = CreateKeyGetID(dataKeyOptions3); var dataKeyId4 = CreateKeyGetID(dataKeyOptions4);
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace). SetKmsProviders(kmsProviders) clientEnc, err := mongo.NewClientEncryption(keyVaultClient, clientEncryptionOpts) if err != nil { return fmt.Errorf("NewClientEncryption error %v", err) } defer func() { _ = clientEnc.Close(context.TODO()) }() dataKeyOpts1 := options.DataKey(). SetKeyAltNames([]string{"demoDataKey1"}) dataKeyID1, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts1) if err != nil { return fmt.Errorf("create data key error %v", err) } dataKeyOpts2 := options.DataKey(). SetKeyAltNames([]string{"demoDataKey2"}) dataKeyID2, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts2) if err != nil { return fmt.Errorf("create data key error %v", err) }
String keyVaultNamespace = keyVaultDb + "." + keyVaultColl; ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder() .keyVaultMongoClientSettings(MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .build()) .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders) .build(); ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings); List<String> keyAlts1 = new ArrayList<String>(); keyAlts1.add("dataKey1"); BsonBinary dataKeyId1 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions() .keyAltNames(keyAlts1)); List<String> keyAlts2 = new ArrayList<String>(); keyAlts2.add("dataKey2"); BsonBinary dataKeyId2 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions() .keyAltNames(keyAlts2));
const clientEnc = new ClientEncryption(keyVaultClient, { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, }); const dek1 = await clientEnc.createDataKey(provider, { keyAltNames: ["dataKey1"], }); const dek2 = await clientEnc.createDataKey(provider, { keyAltNames: ["dataKey2"], });
client = MongoClient(connection_string) client_encryption = ClientEncryption( kms_providers, # pass in the kms_providers variable from the previous step key_vault_namespace, client, CodecOptions(uuid_representation=STANDARD), ) data_key_id_1 = client_encryption.create_data_key(provider, key_alt_names=["dataKey1"]) data_key_id_2 = client_encryption.create_data_key(provider, key_alt_names=["dataKey2"])
创建加密集合
使用已启用 Queryable EncryptionMongoClient
的实例指定必须加密的字段并创建加密的 collection:
var encryptedCollectionNamespace = CollectionNamespace.FromFullName("medicalRecords.patients"); var encryptedFieldsMap = new Dictionary<string, BsonDocument> { { encryptedCollectionNamespace.FullName, new BsonDocument { { "fields", new BsonArray { new BsonDocument { {"keyId", dataKeyId1}, {"path", new BsonString("patientId")}, {"bsonType", new BsonString("int")}, { "queries", new BsonDocument { {"queryType", new BsonString("equality")} } } }, new BsonDocument { {"keyId", dataKeyId2}, {"path", new BsonString("medications")}, {"bsonType", new BsonString("array")}, }, } } } } }; var extraOptions = new Dictionary<string, object>() { { "cryptSharedLibPath", "<path to crypt_shared library>" }, }; var autoEncryptionOptions = new AutoEncryptionOptions( keyVaultNamespace, kmsProviders, encryptedFieldsMap: encryptedFieldsMap, extraOptions: extraOptions); var clientSettings = MongoClientSettings.FromConnectionString(connectionString); clientSettings.AutoEncryptionOptions = autoEncryptionOptions; var secureClient = new MongoClient(clientSettings); var encryptedDatabase = secureClient.GetDatabase(encryptedCollectionNamespace.DatabaseNamespace.DatabaseName); // Drop the encrypted collection in case you created this collection // in a previous run of this application. encryptedDatabase.DropCollection(encryptedCollectionNamespace.CollectionName); encryptedDatabase.CreateCollection(encryptedCollectionNamespace.CollectionName); Console.WriteLine("Created encrypted collection!");
dbName := "medicalRecords" collName := "patients" encNamespace := (dbName + "." + collName) encryptedFieldsMap := bson.M{ encNamespace: bson.M{ "fields": []bson.M{ { "path": "patientId", "bsonType": "int", "keyId": dataKeyID1, "queries": []bson.M{ { "queryType": "equality", }, }, }, { "path": "medications", "bsonType": "array", "keyId": dataKeyID2, }, }, }, } extraOptions := map[string]interface{}{ "cryptSharedLibPath": "<Your Crypt Shared lib Path>", } autoEncryptionOpts := options.AutoEncryption(). SetKmsProviders(kmsProviders). SetKeyVaultNamespace(keyVaultNamespace). SetEncryptedFieldsMap(encryptedFieldsMap). SetExtraOptions(extraOptions) secureClient, 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() { _ = secureClient.Disconnect(context.TODO()) }() // Drop the encrypted collection in case you created this collection // in a previous run of this application. if err = secureClient.Database(dbName).Collection(collName).Drop(context.TODO()); err != nil { log.Fatalf("Collection.Drop error: %v", err) } err = secureClient.Database(dbName).CreateCollection(context.TODO(), collName) if err != nil { return fmt.Errorf("Error creating collection: %v", err) }
String encryptedNameSpace = encryptedDbName + "." + encryptedCollName; BsonDocument encFields = new BsonDocument().append("fields", new BsonArray(Arrays.asList( new BsonDocument().append("keyId", dataKeyId1) .append("path", new BsonString("patientId")) .append("bsonType", new BsonString("int")) .append("queries", new BsonDocument().append("queryType", new BsonString("equality"))), new BsonDocument().append("keyId", dataKeyId2) .append("path", new BsonString("medications")) .append("bsonType", new BsonString("array")), ))); Map<String, BsonDocument> encryptedFieldsMap = new HashMap<String, BsonDocument>(); encryptedFieldsMap.put(encryptedNameSpace, encFields); Map<String, Object> extraOptions = new HashMap<String, Object>(); extraOptions.put("cryptSharedLibPath", "<path to crypt_shared>"); MongoClientSettings clientSettings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .autoEncryptionSettings(AutoEncryptionSettings.builder() .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders) .encryptedFieldsMap(encryptedFieldsMap) .extraOptions(extraOptions) .build()) .build(); MongoClient mongoClientSecure = MongoClients.create(clientSettings); MongoDatabase encDb = mongoClientSecure.getDatabase(encryptedDbName); // Drop the encrypted collection in case you created this collection // in a previous run of this application. encDb.getCollection(encryptedCollName).drop(); encDb.createCollection(encryptedCollName);
const encryptedFieldsMap = { [`${secretDB}.${secretCollection}`]: { fields: [ { keyId: dek1, path: "patientId", bsonType: "int", queries: { queryType: "equality" }, }, { keyId: dek2, path: "medications", bsonType: "array", }, ], }, }; const extraOptions = { cryptSharedLibPath: "<path to FLE Shared Library>", }; const encClient = new MongoClient(uri, { autoEncryption: { keyVaultNamespace, kmsProviders, extraOptions, encryptedFieldsMap, }, }); await encClient.connect(); const newEncDB = encClient.db(secretDB); // Drop the encrypted collection in case you created this collection // in a previous run of this application. await newEncDB.dropDatabase(); await newEncDB.createCollection(secretCollection); console.log("Created encrypted collection!");
encrypted_db_name = "medicalRecords" encrypted_coll_name = "patients" encrypted_fields_map = { f"{encrypted_db_name}.{encrypted_coll_name}": { "fields": [ { "keyId": data_key_id_1, "path": "patientId", "bsonType": "int", "queries": {"queryType": "equality"}, }, { "keyId": data_key_id_2, "path": "medications", "bsonType": "array", }, ], }, } key_vault_namespace = "encryption.__keyVault" auto_encryption = AutoEncryptionOpts( kms_providers, key_vault_namespace, encrypted_fields_map=encrypted_fields_map, crypt_shared_lib_path="<path to FLE Shared Library>", ) secure_client = MongoClient(connection_string, auto_encryption_opts=auto_encryption) # Drop the encrypted collection in case you created this collection # in a previous run of this application. secure_client.drop_database(encrypted_db_name) encrypted_db = secure_client[encrypted_db_name] encrypted_db.create_collection(encrypted_coll_name) print("Created encrypted collection!")
本节中代码的输出应类似于以下内容:
Created encrypted collection!
提示
请参阅:完整代码
要查看制作数据加密密钥的完整代码,请参阅 Queryable Encryption 示例应用程序存储库。
要查看制作数据加密密钥的完整代码,请参阅 Queryable Encryption 示例应用程序存储库。
要查看制作数据加密密钥的完整代码,请参阅 Queryable Encryption 示例应用程序存储库。
要查看制作数据加密密钥的完整代码,请参阅 Queryable Encryption 示例应用程序存储库。
要查看制作数据加密密钥的完整代码,请参阅 Queryable Encryption 示例应用程序存储库。
配置 MongoClient 以进行加密读取和写入
指定密钥保管库集合命名空间
指定 encryption.__keyVault
以作为密钥保管库集合命名空间。
var connectionString = "<Your MongoDB URI>"; var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); var coll = "patients"; var db = "medicalRecords";
keyVaultColl := "__keyVault" keyVaultDb := "encryption" keyVaultNamespace := keyVaultDb + "." + keyVaultColl dbName := "medicalRecords" collName := "patients"
String db = "medicalRecords"; String coll = "patients"; String keyVaultDb = "encryption"; String keyVaultColl = "__keyVault"; String keyVaultNamespace = String.format("%1$s.%2$s", keyVaultDb, keyVaultColl); String connectionString = "<Your MongoDB URI>";
const eDB = "encryption"; const eKV = "__keyVault"; const keyVaultNamespace = `${eDB}.${eKV}`; const secretDB = "medicalRecords"; const secretCollection = "patients";
key_vault_namespace = "encryption.__keyVault" key_vault_db_name, key_vault_coll_name = key_vault_namespace.split(".", 1)
指定客户主密钥
指定 KMS 提供商并以内联方式指定客户主密钥:
var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>(); const string provider = "local"; const string localMasterKeyPath = "master-key.txt"; var localMasterKeyBase64Read = File.ReadAllText(localMasterKeyPath); var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read); var localOptions = new Dictionary<string, object> { {"key", localMasterKeyBytes} }; kmsProviders.Add(provider, localOptions);
key, err := ioutil.ReadFile("master-key.txt") if err != nil { log.Fatalf("Could not read the key from master-key.txt: %v", err) } kmsProviders := map[string]map[string]interface{}{"local": {"key": key}}
String kmsProvider = "local"; String path = "master-key.txt"; byte[] localMasterKeyRead = new byte[96]; try (FileInputStream fis = new FileInputStream(path)) { if (fis.read(localMasterKeyRead) < 96) throw new Exception("Expected to read 96 bytes from file"); } Map<String, Object> keyMap = new HashMap<>(); keyMap.put("key", localMasterKeyRead); Map<String, Map<String, Object>> kmsProviders = new HashMap<>(); kmsProviders.put(kmsProvider, keyMap);
const fs = require("fs"); const path = "./master-key.txt"; // WARNING: Do not use a local key file in a production application const localMasterKey = fs.readFileSync(path); const kmsProviders = { local: { key: localMasterKey, }, };
path = "./master-key.txt" with open(path, "rb") as f: local_master_key = f.read() kms_providers = { "local": { "key": local_master_key # local_master_key variable from the previous step }, }
检索数据加密密钥
检索在本指南的“创建数据加密密钥”步骤中创建的数据加密密钥:
var regularClient = new MongoClient(connectionString); var keyVaultCollection = regularClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName) .GetCollection<BsonDocument>(keyVaultNamespace.CollectionName); Guid GetKeyId(string altName) { var filter = Builders<BsonDocument>.Filter.Eq<BsonString>("keyAltNames", altName); return keyVaultCollection.Find(filter).First<BsonDocument>()["_id"].AsGuid; } var dataKeyId1 = GetKeyId("dataKey1"); var dataKeyId2 = GetKeyId("dataKey2");
uri := "<Your MongoDB URI>" regularClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)) if err != nil { panic(fmt.Errorf("Client connect error %v", err)) } var foundDoc1 bson.M err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey1"}}).Decode(&foundDoc1) if err != nil { panic(err) } var dataKeyID1 = foundDoc1["_id"].(primitive.Binary) var foundDoc2 bson.M err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey2"}}).Decode(&foundDoc2) if err != nil { panic(err) } var dataKeyID2 = foundDoc2["_id"].(primitive.Binary)
MongoClient client = MongoClients.create(connectionString); MongoCollection<Document> keyVaultClient = client.getDatabase(keyVaultDb).getCollection(keyVaultColl); BsonBinary dataKeyId1 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey1")).first().get("_id", Binary.class).getData()); BsonBinary dataKeyId2 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey2")).first().get("_id", Binary.class).getData());
const uri = "<Your MongoDB URI>"; const unencryptedClient = new MongoClient(uri); await unencryptedClient.connect(); const keyVaultClient = unencryptedClient.db(eDB).collection(eKV); const dek1 = await keyVaultClient.findOne({ keyAltNames: "dataKey1" }); const dek2 = await keyVaultClient.findOne({ keyAltNames: "dataKey2" });
connection_string = "<your connection string here>" client = MongoClient(connection_string) key_vault = client[key_vault_db_name][key_vault_coll_name] data_key_id_1 = key_vault.find_one({"keyAltNames": "dataKey1"})["_id"] data_key_id_2 = key_vault.find_one({"keyAltNames": "dataKey2"})["_id"]
指定自动加密共享库的路径
var extraOptions = new Dictionary<string, object>() { {"cryptSharedLibPath", "<path to crypt_shared library>"}, };
extraOptions := map[string]interface{}{ "cryptSharedLibPath": "<path to crypt_shared library>", }
Map<String, Object> extraOptions = new HashMap<>(); extraOptions.put("cryptSharedLibPath", "<path to crypt_shared library>");
const extraOptions = { cryptSharedLibPath: "<path to crypt_shared library>", };
opts = AutoEncryptionOpts( kms_providers, key_vault.full_name, bypass_query_analysis=True, key_vault_client=client, crypt_shared_lib_path="<path to FLE Shared Library>", )
创建 MongoClient 对象
使用以下自动加密设置实例化MongoClient
对象:
var clientSettings = MongoClientSettings.FromConnectionString(connectionString); var autoEncryptionOptions = new AutoEncryptionOptions( keyVaultNamespace, kmsProviders, bypassQueryAnalysis: true, extraOptions: extraOptions); clientSettings.AutoEncryptionOptions = autoEncryptionOptions; var secureClient = new MongoClient(clientSettings); var collection = secureClient.GetDatabase(db).GetCollection<BsonDocument>(coll);
autoEncryptionOpts := options.AutoEncryption(). SetKmsProviders(kmsProviders). SetKeyVaultNamespace(keyVaultNamespace). SetExtraOptions(extraOptions). SetBypassQueryAnalysis(true) secureClient, 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() { _ = secureClient.Disconnect(context.TODO()) }() var coll = secureClient.Database(dbName).Collection(collName)
MongoClientSettings clientSettings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .autoEncryptionSettings(AutoEncryptionSettings.builder() .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders) .extraOptions(extraOptions) .bypassQueryAnalysis(true) .build()) .build(); MongoClient mongoClientSecure = MongoClients.create(clientSettings);
const encryptedClient = new MongoClient(uri, { autoEncryption: { kmsProviders: kmsProviders, keyVaultNamespace: keyVaultNamespace, bypassQueryAnalysis: true, keyVaultClient: unencryptedClient, extraOptions: extraOptions, }, }); await encryptedClient.connect();
encrypted_client = MongoClient(connection_string, auto_encryption_opts=opts) db = encrypted_client.medicalRecords coll = db.patients
创建 ClientEncryption 对象
按如下方式实例化一个ClientEncryption
对象:
var clientEncryptionOptions = new ClientEncryptionOptions( keyVaultClient: regularClient, keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders ); var clientEncryption = new ClientEncryption(clientEncryptionOptions);
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace).SetKmsProviders(kmsProviders) clientEnc, err := mongo.NewClientEncryption(regularClient, clientEncryptionOpts) if err != nil { panic(fmt.Errorf("NewClientEncryption error %v", err)) } defer func() { _ = clientEnc.Close(context.TODO()) }()
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder() .keyVaultMongoClientSettings(MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .build()) .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders) .build(); ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
const encryption = new ClientEncryption(unencryptedClient, { keyVaultNamespace, kmsProviders, });
client_encryption = ClientEncryption( kms_providers, key_vault_namespace, client, client.codec_options )
插入具有加密字段的文档
使用已启用 Queryable Encryption 的MongoClient
实例,通过以下代码段将具有加密字段的文档插入到medicalRecords.patients
命名空间中:
var patientId = 12345678; var medications = new BsonArray { new BsonString("Atorvastatin"), new BsonString("Levothyroxine") }; var indexedEncrypted = clientEncryption.Encrypt( patientId, new EncryptOptions(algorithm: "Indexed", keyId: dataKeyId1, contentionFactor: 1), CancellationToken.None); var unindexedEncrypted = clientEncryption.Encrypt( medications, new EncryptOptions(algorithm: "Unindexed", keyId: dataKeyId2), CancellationToken.None); collection.InsertOne(new BsonDocument { { "firstName", "Jon" }, { "patientId", indexedEncrypted }, { "medications", unindexedEncrypted } });
patientIdRawValueType, patientIdRawValueData, err := bson.MarshalValue(12345678) if err != nil { panic(err) } patientIdRawValue := bson.RawValue{Type: patientIdRawValueType, Value: patientIdRawValueData} patientIdEncryptionOpts := options.Encrypt(). SetAlgorithm("Indexed"). SetKeyID(dataKeyID1). SetContentionFactor(1) patientIdEncryptedField, err := clientEnc.Encrypt( context.TODO(), patientIdRawValue, patientIdEncryptionOpts) if err != nil { panic(err) } medicationsRawValueType, medicationsRawValueData, err := bson.MarshalValue([]string{"Atorvastatin", "Levothyroxine"}) if err != nil { panic(err) } medicationsRawValue := bson.RawValue{Type: medicationsRawValueType, Value: medicationsRawValueData} medicationsEncryptionOpts := options.Encrypt(). SetAlgorithm("Unindexed"). SetKeyID(dataKeyID2) medicationsEncryptedField, err := clientEnc.Encrypt( context.TODO(), medicationsRawValue, medicationsEncryptionOpts) if err != nil { panic(err) } _, err = coll.InsertOne( context.TODO(), bson.D{{"firstName", "Jon"}, {"patientId", patientIdEncryptedField}, {"medications", medicationsEncryptedField}}) if err != nil { panic(err) }
BsonInt32 patientId = new BsonInt32(12345678); ArrayList<BsonString> medications = new ArrayList<>(); medications.add(new BsonString("Atorvastatin")); medications.add(new BsonString("Levothyroxine")); BsonBinary indexedEncrypted = clientEncryption.encrypt(patientId, new EncryptOptions("Indexed").keyId(dataKeyId1).contentionFactor(1L)); BsonBinary unindexedEncrypted = clientEncryption.encrypt(new BsonArray(medications), new EncryptOptions("Unindexed").keyId(dataKeyId2)); MongoCollection<BsonDocument> collection = mongoClientSecure.getDatabase(db).getCollection(coll, BsonDocument.class); collection.insertOne(new BsonDocument("firstName", new BsonString("Jon")).append("patientId", indexedEncrypted).append("medications", unindexedEncrypted));
const patientId = 12345678; const medications = ["Atorvastatin", "Levothyroxine"]; const indexedInsertPayload = await encryption.encrypt(patientId, { algorithm: "Indexed", keyId: dek1._id, contentionFactor: 1, }); const unindexedInsertPayload = await encryption.encrypt(medications, { algorithm: "Unindexed", keyId: dek2._id, }); const encryptedColl = encryptedClient .db(secretDB) .collection(secretCollection); await encryptedColl.insertOne({ firstName: "Jon", patientId: indexedInsertPayload, medications: unindexedInsertPayload, });
patientId = 12345678 medications = ["Atorvastatin", "Levothyroxine"] indexed_insert_payload = client_encryption.encrypt( patientId, Algorithm.INDEXED, data_key_id_1, contention_factor=1 ) unindexed_insert_payload = client_encryption.encrypt( medications, Algorithm.UNINDEXED, data_key_id_2 ) coll.insert_one( { "firstName": "Jon", "patientId": indexed_insert_payload, "medications": unindexed_insert_payload, } )
插入文档时,启用了 Queryable Encryption 的客户端会对文档的字段进行加密,如下所示:
{ "_id": { "$oid": "6303e36053cc7ec2e6a630bd" }, "firstName": "Jon", "patientId": { "$binary": { "base64": "BxLJUBmg703civqMz8ASsD4QEYeSneOGiiYHfLE77ELEkp1EC/fXPrKCNRQl2mAFddszqDJ0P3znKrq0DVMEvJoU6wa0Ra+U+JjNVr8NtJE+TpTLCannY5Av6iGfLAaiHbM/E8Ftz1YCQsArQwuNp3wIV/GJPLa2662xsyk0wz7F6IRGC3FlnxpN4UIFaHE1M7Y6kEnx3tEy5uJBvU4Sex7I2H0kqHthClH77Q6xHIHc8H9d6upvgnEbkKBCnmc24A2pSG/xZ7LBsV3j5aOboPISuN/lvg==", "subType": "06" } }, "medications": { "$binary": { "base64": "BvOsveapfUxiuQxCMSM2fYIEyRlQaSqR+0NxlMarwurBflvoMz1FrSjSGgCVCpK8X+YrilP6Bac99kkaUmRJfjo4savxcjpOfEnUj5bHciPyfQBYmYF4PMLDtTTzGZpPilb9d5KgpIMBXxHi+dIcog==", "subType": "06" } }, "__safeContent__": [ { "$binary": { "base64": "ZLPIpgxzXpHUGrvdIHetwmMagR+mqvuUj5nzXNGf/WM=", "subType": "00" } } ] }
警告
不要修改 __safeContent__ 字段
__safeContent__
字段对于 Queryable Encryption 至关重要。请勿修改此字段的内容。
提示
请参阅:完整代码
要查看插入通过显式加密加密的文档的完整代码,请参阅 可查询Queryable Encryption 示例应用程序存储库。
要查看插入通过显式加密加密的文档的完整代码,请参阅 可查询Queryable Encryption 示例应用程序存储库。
要查看插入通过显式加密加密的文档的完整代码,请参阅 可查询Queryable Encryption 示例应用程序存储库。
要查看插入通过显式加密加密的文档的完整代码,请参阅 可查询Queryable Encryption 示例应用程序存储库。
要查看插入通过显式加密加密的文档的完整代码,请参阅 可查询Queryable Encryption 示例应用程序存储库。
检索具有加密字段的文档
通过对加密字段进行查询,检索在本指南的“插入具有加密字段的文档”步骤中插入的具有加密字段的文档:
var findPayload = clientEncryption.Encrypt( patientId, new EncryptOptions(algorithm: "Indexed", keyId: dataKeyId1, queryType: "equality", contentionFactor: 1), CancellationToken.None); var doc = collection.Find(new BsonDocument { { "patientId", findPayload } }).Single(); Console.WriteLine($"Encrypted document: {doc}");
findPayloadRawValueType, findPayloadRawValueData, err := bson.MarshalValue(12345678) if err != nil { panic(err) } findPayloadRawValue := bson.RawValue{Type: findPayloadRawValueType, Value: findPayloadRawValueData} findPayloadEncryptionOpts := options.Encrypt(). SetAlgorithm("Indexed"). SetKeyID(dataKeyID1). SetQueryType("equality"). SetContentionFactor(1) findPayloadEncryptedField, err := clientEnc.Encrypt( context.TODO(), findPayloadRawValue, findPayloadEncryptionOpts) if err != nil { panic(err) } var resultSecure bson.M coll.FindOne(context.TODO(), bson.D{{"firstName", findPayloadEncryptedField}}).Decode(&resultSecure) if err != nil { panic(err) } outputSecure, err := json.MarshalIndent(resultSecure, "", " ") if err != nil { panic(err) } fmt.Printf("\nFound document searching on explicitly encrypted field:\n%s\n", outputSecure)
BsonBinary findPayloadEncrypted = clientEncryption.encrypt(patientId, new EncryptOptions("Indexed").keyId(dataKeyId1).queryType("equality").contentionFactor(1L)); BsonDocument result = collection.find(eq("patientId", findPayloadEncrypted)).first(); System.out.println("Finding a document with manually encrypted field: " + result.toJson());
const findPayload = await encryption.encrypt(patientId, { algorithm: "Indexed", keyId: dek1._id, queryType: "equality", contentionFactor: 1, }); console.log("Finding a document with manually encrypted field:"); console.log(await encryptedColl.findOne({ patientId: findPayload }));
find_payload = client_encryption.encrypt( patientId, Algorithm.INDEXED, data_key_id_1, query_type=QueryType.EQUALITY, contention_factor=1, ) doc = coll.find_one({"encryptedIndexed": find_payload}) print("\nReturned document:\n") pprint.pprint(doc)
上述代码片段的输出应包含以下文档:
{ "__safeContent__": [ { "Subtype": 0, "Data": "LfaIuWm9o30MIGrK7GGUoStJMSNOjRgbxy5q2TPiDes=" } ], "_id": "6303a770857952ca5e363fd2", "firstName": "Jon", "medications": ["Atorvastatin", "Levothyroxine"], "patientId": 12345678 }
提示
请参阅:完整代码
要查看使用加密字段检索文档的代码,请参阅 可查询加密示例应用程序存储库。
要查看使用加密字段检索文档的代码,请参阅 可查询加密示例应用程序存储库。
要查看使用加密字段检索文档的代码,请参阅 可查询加密示例应用程序存储库。
要查看使用加密字段检索文档的代码,请参阅 可查询加密示例应用程序存储库。
要查看使用加密字段检索文档的代码,请参阅 可查询加密示例应用程序存储库。
了解详情
要查看有关将 Queryable Encryption 与远程 KMS 结合使用的教程,请参阅教程。
要了解Queryable Encryption的工作原理,请参阅显式加密。
如需详细了解本指南中提到的主题,请参阅以下链接: