正在使用的加密提供了两项功能来加密MongoDB集合中的敏感数据:
客户端字段级加密 — 加密客户端的特定数据字段
Queryable Encryption - 加密数据,同时保持查询加密字段的能力
这两种功能都提供 ACID 一致性保证,确保未经授权的各方(包括服务器管理员)无法读取加密数据。
安装
您必须将 libmongocrypt 作为依赖项安装,才能使用“正在使用的加密”。有关完整的安装指南,请参阅MongoDB Server手册中的 libmongocrypt 安装说明。
安装 libmongocrypt 后,使用 -DENABLE_CLIENT_SIDE_ENCRYPTION=ON 配置 C 驱动程序以启用“正在使用的加密”,如以下示例所示:
$ cd mongo-c-driver $ mkdir cmake-build && cd cmake-build $ cmake -DENABLE_CLIENT_SIDE_ENCRYPTION=ON .. $ cmake --build . --target install
查询分析
要支持自动加密,您需要以下依赖项之一:
mongocryptd可执行文件。有关安装说明,请参阅MongoDB Server手册中的mongocryptd指南。crypt_shared库。有关更多信息,请参阅MongoDB Server手册中的自动加密指南。
配置了自动加密的 mongoc_client_t 或 mongoc_client_pool_t 会自动尝试加载 crypt_shared 库。如果加载 crypt_shared 库失败,mongoc_client_t 或 mongoc_client_pool_t 会尝试从应用程序的 PATH 生成 mongocryptd进程。要配置使用 crypt_shared 和 mongocryptd,请参阅 mongoc_auto_encryption_opts_set_extra。
API
使用 mongoc_client_encryption_t 进行显式加密和密钥管理。使用 mongoc_client_enable_auto_encryption 和 mongoc_client_pool_enable_auto_encryption启用自动加密。
Queryable Encryption(QE) 和客户端字段级加密(CSFLE) 功能具有许多相同的API,但有一些例外:
mongoc_client_encryption_encrypt_opts_set_algorithm 中记录的支持算法不适应用这两种功能。
mongoc_auto_encryption_opts_set_encrypted_fields_map 应用于 Queryable Encryption。
mongoc_auto_encryption_opts_set_schema_map 仅应用于 CSFLE。
客户端字段级加密 (Client-Side Field Level Encryption)
除了其他MongoDB加密功能外,CSFLE 还使管理员和开发者能够加密特定数据字段。
通过使用 CSFLE,您可以加密客户端字段,而无需任何服务器端配置或指令。CSFLE 支持的工作负载中,应用程序必须保证未经授权方(包括服务器管理员)无法读取加密数据。
自动加密(即自动加密命令中的敏感字段)需要仅针对 Enterprise 的依赖项进行查询分析。有关更多信息,请参阅查询分析。
提示
自动客户端字段级加密
通过在 mongoc_client_t 对象上调用 mongoc_client_enable_auto_encryption 来启用自动加密。以下示例展示如何使用 mongoc_client_encryption_t 创建新的加密数据密钥来设立自动加密。
注意
自动加密需要MongoDB Enterprise Advanced 4.2 或更高版本,或者MongoDB 4.2 或更高版本的Atlas 集群。MongoDB Server的社区版本支持自动解密和显式加密。
提供本地自动加密规则
您可以使用模式映射指定自动加密规则。要创建模式映射,请调用 mongoc_auto_encryption_opts_set_schema_map 函数。自动加密规则使用严格的JSON Schema语法子集。
与依赖从服务器获取的JSON schemas 相比,提供模式映射可提供更高的安全性。 它可以防止恶意服务器公布虚假JSON schema,这种情况可能会诱骗客户端发送应加密的未加密数据。
模式映射中提供的JSON模式仅应用于配置自动加密。JSON schema中的其他验证规则不会由驱动程序执行,从而导致错误。
以下示例使用 mongoc_auto_encryption_opts_set_schema_map() 函数创建指定自动加密规则的模式映射:
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes. int main(void) { bson_error_t error; // The key vault collection stores encrypted data keys: const char *keyvault_db_name = "keyvault"; const char *keyvault_coll_name = "datakeys"; // The encrypted collection stores application data: const char *encrypted_db_name = "db"; const char *encrypted_coll_name = "coll"; // Set `local_key` to a 96 byte base64-encoded string: const char *local_key = "qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/" "QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK"; const char *uri = "mongodb://localhost/?appname=client-side-encryption"; mongoc_init(); // Configure KMS providers used to encrypt data keys: bson_t kms_providers; { char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key); init_bson(kms_providers, as_json); bson_free(as_json); } // Set up key vault collection: mongoc_client_t *keyvault_client; { keyvault_client = mongoc_client_new(uri); if (!keyvault_client) { FAIL("Failed to create keyvault client"); } mongoc_collection_t *coll = mongoc_client_get_collection(keyvault_client, keyvault_db_name, keyvault_coll_name); mongoc_collection_drop(coll, NULL); // Clear pre-existing data. // Create index to ensure keys have unique keyAltNames: bson_t index_keys, index_opts; init_bson(index_keys, BSON_STR({"keyAltNames" : 1})); init_bson(index_opts, BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}})); mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts); if (!mongoc_collection_create_indexes_with_opts( coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to create index: %s", error.message); } mongoc_index_model_destroy(index_model); bson_destroy(&index_opts); bson_destroy(&index_keys); mongoc_collection_destroy(coll); } // Create ClientEncryption object: mongoc_client_encryption_t *client_encryption; { mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new(); mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name); mongoc_client_encryption_opts_set_keyvault_client(ce_opts, keyvault_client); client_encryption = mongoc_client_encryption_new(ce_opts, &error); if (!client_encryption) { FAIL("Failed to create ClientEncryption: %s", error.message); } mongoc_client_encryption_opts_destroy(ce_opts); } // Create data key (see: // https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules): bson_value_t datakey_id; { mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new(); if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) { FAIL("Failed to create data key: %s", error.message); } mongoc_client_encryption_datakey_opts_destroy(dk_opts); } // Create a schema map: bson_t schema_map = BSON_INITIALIZER; { /* { "db.coll": { "properties" : { "encryptedField" : { "encrypt" : { "keyId" : [ "<key ID>" ], "bsonType" : "string", "algorithm" : "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType" : "object" } } */ bson_t key_ids = BSON_INITIALIZER; BSON_APPEND_VALUE(&key_ids, "0", &datakey_id); bson_t encrypt = BSON_INITIALIZER; BSON_APPEND_ARRAY(&encrypt, "keyId", &key_ids); BSON_APPEND_UTF8(&encrypt, "bsonType", "string"); BSON_APPEND_UTF8(&encrypt, "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"); bson_t encryptedField = BSON_INITIALIZER; BSON_APPEND_DOCUMENT(&encryptedField, "encrypt", &encrypt); bson_t properties = BSON_INITIALIZER; BSON_APPEND_DOCUMENT(&properties, "encryptedField", &encryptedField); bson_t db_coll = BSON_INITIALIZER; BSON_APPEND_DOCUMENT(&db_coll, "properties", &properties); BSON_APPEND_UTF8(&db_coll, "bsonType", "object"); BSON_APPEND_DOCUMENT(&schema_map, "db.coll", &db_coll); bson_destroy(&key_ids); bson_destroy(&db_coll); bson_destroy(&encrypt); bson_destroy(&encryptedField); bson_destroy(&properties); } // Create client configured to automatically encrypt: mongoc_client_t *encrypted_client; { encrypted_client = mongoc_client_new(uri); if (!encrypted_client) { FAIL("Failed to create client"); } mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new(); mongoc_auto_encryption_opts_set_schema_map(ae_opts, &schema_map); mongoc_auto_encryption_opts_set_keyvault_namespace(ae_opts, keyvault_db_name, keyvault_coll_name); mongoc_auto_encryption_opts_set_kms_providers(ae_opts, &kms_providers); if (!mongoc_client_enable_auto_encryption(encrypted_client, ae_opts, &error)) { FAIL("Failed to enable auto encryption: %s", error.message); } mongoc_auto_encryption_opts_destroy(ae_opts); } // Insert a document: mongoc_collection_t *encrypted_coll = mongoc_client_get_collection(encrypted_client, encrypted_db_name, encrypted_coll_name); { mongoc_collection_drop(encrypted_coll, NULL); // Clear pre-existing data. bson_t to_insert = BSON_INITIALIZER; BSON_APPEND_UTF8(&to_insert, "encryptedField", "foobar"); if (!mongoc_collection_insert_one(encrypted_coll, &to_insert, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to insert: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(&to_insert, NULL); printf("Inserted document with automatic encryption: %s\n", as_str); bson_free(as_str); bson_destroy(&to_insert); } // Retrieve document with automatic decryption: { bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(encrypted_coll, &filter, NULL, NULL); const bson_t *result; if (!mongoc_cursor_next(cursor, &result)) { FAIL("Failed to find inserted document: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(result, NULL); printf("Retrieved document with automatic decryption: %s\n", as_str); bson_free(as_str); mongoc_cursor_destroy(cursor); bson_destroy(&filter); } // Retrieve document without decryption: { mongoc_collection_t *unencrypted_coll = mongoc_client_get_collection(keyvault_client, encrypted_db_name, encrypted_coll_name); bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(unencrypted_coll, &filter, NULL, NULL); const bson_t *result; if (!mongoc_cursor_next(cursor, &result)) { FAIL("Failed to find inserted document: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(result, NULL); printf("Retrieved document without automatic decryption: %s\n", as_str); bson_free(as_str); mongoc_cursor_destroy(cursor); bson_destroy(&filter); mongoc_collection_destroy(unencrypted_coll); } mongoc_collection_destroy(encrypted_coll); mongoc_client_destroy(encrypted_client); bson_destroy(&schema_map); bson_value_destroy(&datakey_id); mongoc_client_encryption_destroy(client_encryption); bson_destroy(&kms_providers); mongoc_client_destroy(keyvault_client); mongoc_cleanup(); return 0; }
服务器端字段级加密实施
MongoDB Server支持使用模式验证来实施对集合中的特定字段加密。此模式验证可防止应用程序为任何标有 encrypt JSON Schema 关键字的字段插入未加密的值。
要实现服务器端强制执行,必须创建加密数据密钥和配置有相应JSON模式验证规则的集合,如以下示例所示:
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes. int main(void) { bson_error_t error; // The key vault collection stores encrypted data keys: const char *keyvault_db_name = "keyvault"; const char *keyvault_coll_name = "datakeys"; // The encrypted collection stores application data: const char *encrypted_db_name = "db"; const char *encrypted_coll_name = "coll"; // Set `local_key` to a 96 byte base64-encoded string: const char *local_key = "qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/" "QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK"; const char *uri = "mongodb://localhost/?appname=client-side-encryption"; mongoc_init(); // Configure KMS providers used to encrypt data keys: bson_t kms_providers; { char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key); init_bson(kms_providers, as_json); bson_free(as_json); } // Set up key vault collection: mongoc_client_t *keyvault_client; { keyvault_client = mongoc_client_new(uri); if (!keyvault_client) { FAIL("Failed to create keyvault client"); } mongoc_collection_t *coll = mongoc_client_get_collection(keyvault_client, keyvault_db_name, keyvault_coll_name); mongoc_collection_drop(coll, NULL); // Clear pre-existing data. // Create index to ensure keys have unique keyAltNames: bson_t index_keys, index_opts; init_bson(index_keys, BSON_STR({"keyAltNames" : 1})); init_bson(index_opts, BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}})); mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts); if (!mongoc_collection_create_indexes_with_opts( coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to create index: %s", error.message); } mongoc_index_model_destroy(index_model); bson_destroy(&index_opts); bson_destroy(&index_keys); mongoc_collection_destroy(coll); } // Create ClientEncryption object: mongoc_client_encryption_t *client_encryption; { mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new(); mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name); mongoc_client_encryption_opts_set_keyvault_client(ce_opts, keyvault_client); client_encryption = mongoc_client_encryption_new(ce_opts, &error); if (!client_encryption) { FAIL("Failed to create ClientEncryption: %s", error.message); } mongoc_client_encryption_opts_destroy(ce_opts); } // Create data key (see: // https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules): bson_value_t datakey_id; { mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new(); if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) { FAIL("Failed to create data key: %s", error.message); } mongoc_client_encryption_datakey_opts_destroy(dk_opts); } // Create collection with remote schema: bson_t schema = BSON_INITIALIZER; { /* { "properties" : { "encryptedField" : { "encrypt" : { "keyId" : [ "<key ID>" ], "bsonType" : "string", "algorithm" : "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType" : "object" } */ bson_t key_ids = BSON_INITIALIZER; BSON_APPEND_VALUE(&key_ids, "0", &datakey_id); bson_t encrypt = BSON_INITIALIZER; BSON_APPEND_ARRAY(&encrypt, "keyId", &key_ids); BSON_APPEND_UTF8(&encrypt, "bsonType", "string"); BSON_APPEND_UTF8(&encrypt, "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"); bson_t encryptedField = BSON_INITIALIZER; BSON_APPEND_DOCUMENT(&encryptedField, "encrypt", &encrypt); bson_t properties = BSON_INITIALIZER; BSON_APPEND_DOCUMENT(&properties, "encryptedField", &encryptedField); BSON_APPEND_DOCUMENT(&schema, "properties", &properties); BSON_APPEND_UTF8(&schema, "bsonType", "object"); bson_destroy(&key_ids); bson_destroy(&encrypt); bson_destroy(&encryptedField); bson_destroy(&properties); } // Create client configured to automatically encrypt: mongoc_client_t *encrypted_client; { encrypted_client = mongoc_client_new(uri); if (!encrypted_client) { FAIL("Failed to create client"); } mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new(); mongoc_auto_encryption_opts_set_keyvault_namespace(ae_opts, keyvault_db_name, keyvault_coll_name); mongoc_auto_encryption_opts_set_kms_providers(ae_opts, &kms_providers); if (!mongoc_client_enable_auto_encryption(encrypted_client, ae_opts, &error)) { FAIL("Failed to enable auto encryption: %s", error.message); } mongoc_auto_encryption_opts_destroy(ae_opts); } // Clear pre-existing data: { mongoc_collection_t *coll = mongoc_client_get_collection(encrypted_client, encrypted_db_name, encrypted_coll_name); mongoc_collection_drop(coll, NULL); mongoc_collection_destroy(coll); } // Create collection with server-side schema: mongoc_collection_t *encrypted_coll; { mongoc_database_t *db = mongoc_client_get_database(encrypted_client, encrypted_db_name); bson_t create_opts = BSON_INITIALIZER; // { validator: { $jsonSchema: <schema> } } bson_t json_schema = BSON_INITIALIZER; BSON_APPEND_DOCUMENT(&json_schema, "$jsonSchema", &schema); BSON_APPEND_DOCUMENT(&create_opts, "validator", &json_schema); encrypted_coll = mongoc_database_create_collection(db, encrypted_coll_name, &create_opts, &error); if (!encrypted_coll) { FAIL("Failed to create collection: %s", error.message); } bson_destroy(&json_schema); bson_destroy(&create_opts); mongoc_database_destroy(db); } // Insert a document: { bson_t to_insert = BSON_INITIALIZER; BSON_APPEND_UTF8(&to_insert, "encryptedField", "foobar"); if (!mongoc_collection_insert_one(encrypted_coll, &to_insert, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to insert: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(&to_insert, NULL); printf("Inserted document with automatic encryption: %s\n", as_str); bson_free(as_str); bson_destroy(&to_insert); } // Retrieve document with automatic decryption: { bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(encrypted_coll, &filter, NULL, NULL); const bson_t *result; if (!mongoc_cursor_next(cursor, &result)) { FAIL("Failed to find inserted document: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(result, NULL); printf("Retrieved document with automatic decryption: %s\n", as_str); bson_free(as_str); mongoc_cursor_destroy(cursor); bson_destroy(&filter); } // Retrieve document without automatic decryption: { mongoc_collection_t *unencrypted_coll = mongoc_client_get_collection(keyvault_client, encrypted_db_name, encrypted_coll_name); bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(unencrypted_coll, &filter, NULL, NULL); const bson_t *result; if (!mongoc_cursor_next(cursor, &result)) { FAIL("Failed to find inserted document: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(result, NULL); printf("Retrieved document without automatic decryption: %s\n", as_str); bson_free(as_str); mongoc_cursor_destroy(cursor); bson_destroy(&filter); mongoc_collection_destroy(unencrypted_coll); } mongoc_collection_destroy(encrypted_coll); bson_value_destroy(&datakey_id); mongoc_client_destroy(encrypted_client); bson_destroy(&schema); mongoc_client_encryption_destroy(client_encryption); bson_destroy(&kms_providers); mongoc_client_destroy(keyvault_client); mongoc_cleanup(); return 0; }
显式加密
您可以使用显式加密来指定如何为对数据库执行的每个操作加密文档中的字段。使用显式加密时,您必须定义自己的加密数据密钥和加密选项。
显式加密是MongoDB Community Edition 的一项功能,不使用查询分析(mongocryptd 或 crypt_shared)。显式加密使用 mongoc_client_encryption_t 类。以下示例演示了如何使用显式加密和解密:
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes. int main(void) { bson_error_t error; // The key vault collection stores encrypted data keys: const char *keyvault_db_name = "keyvault"; const char *keyvault_coll_name = "datakeys"; // Set `local_key` to a 96 byte base64-encoded string: const char *local_key = "qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/" "QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK"; const char *uri = "mongodb://localhost/?appname=client-side-encryption"; mongoc_init(); // Create client: mongoc_client_t *client = mongoc_client_new(uri); if (!client) { FAIL("Failed to create client"); } // Configure KMS providers used to encrypt data keys: bson_t kms_providers; { char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key); init_bson(kms_providers, as_json); bson_free(as_json); } // Set up key vault collection: { mongoc_collection_t *coll = mongoc_client_get_collection(client, keyvault_db_name, keyvault_coll_name); mongoc_collection_drop(coll, NULL); // Clear pre-existing data. // Create index to ensure keys have unique keyAltNames: bson_t index_keys, index_opts; init_bson(index_keys, BSON_STR({"keyAltNames" : 1})); init_bson(index_opts, BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}})); mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts); if (!mongoc_collection_create_indexes_with_opts( coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to create index: %s", error.message); } mongoc_index_model_destroy(index_model); bson_destroy(&index_opts); bson_destroy(&index_keys); mongoc_collection_destroy(coll); } // Create ClientEncryption object: mongoc_client_encryption_t *client_encryption; { mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new(); mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name); mongoc_client_encryption_opts_set_keyvault_client(ce_opts, client); client_encryption = mongoc_client_encryption_new(ce_opts, &error); if (!client_encryption) { FAIL("Failed to create ClientEncryption: %s", error.message); } mongoc_client_encryption_opts_destroy(ce_opts); } // Create data key (see: // https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules): bson_value_t datakey_id; { mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new(); if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) { FAIL("Failed to create data key: %s", error.message); } mongoc_client_encryption_datakey_opts_destroy(dk_opts); } // Explicitly encrypt a value: bson_value_t encrypted_value; { mongoc_client_encryption_encrypt_opts_t *e_opts = mongoc_client_encryption_encrypt_opts_new(); mongoc_client_encryption_encrypt_opts_set_algorithm(e_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC); mongoc_client_encryption_encrypt_opts_set_keyid(e_opts, &datakey_id); bson_value_t to_encrypt = {.value_type = BSON_TYPE_INT32, .value = {.v_int32 = 123}}; if (!mongoc_client_encryption_encrypt(client_encryption, &to_encrypt, e_opts, &encrypted_value, &error)) { FAIL("Failed to encrypt field: %s", error.message); } mongoc_client_encryption_encrypt_opts_destroy(e_opts); } // Explicitly decrypt a value: { bson_value_t decrypted_value; if (!mongoc_client_encryption_decrypt(client_encryption, &encrypted_value, &decrypted_value, &error)) { FAIL("Failed to decrypt field: %s", error.message); } printf("Decrypted value: %" PRId32 "\n", decrypted_value.value.v_int32); bson_value_destroy(&decrypted_value); } bson_value_destroy(&encrypted_value); bson_value_destroy(&datakey_id); mongoc_client_encryption_destroy(client_encryption); bson_destroy(&kms_providers); mongoc_client_destroy(client); mongoc_cleanup(); return 0; }
带自动解密的显式加密
虽然自动加密需要MongoDB Enterprise Advanced或MongoDB Atlas 集群,但所有MongoDB Server产品都支持自动解密。要配置具有自动解密功能的显式加密,请在 mongoc_auto_encryption_opts_t 中设立bypass_auto_encryption=True,如以下示例所示:
// `init_bson` creates BSON from JSON. Aborts on error. Use the `BSON_STR()` macro to avoid quotes. int main(void) { bson_error_t error; // The key vault collection stores encrypted data keys: const char *keyvault_db_name = "keyvault"; const char *keyvault_coll_name = "datakeys"; // The encrypted collection stores application data: const char *encrypted_db_name = "db"; const char *encrypted_coll_name = "coll"; // Set `local_key` to a 96 byte base64-encoded string: const char *local_key = "qx/3ydlPRXgUrBvSBWLsllUTaYDcS/pyaVo27qBHkS2AFePjInwhzCmDWHdmCYPmzhO4lRBzeZKFjSafduLL5z5DMvR/" "QFfV4zc7btcVmV3QWbDwqZyn6G+Y18ToLHyK"; const char *uri = "mongodb://localhost/?appname=client-side-encryption"; mongoc_init(); // Configure KMS providers used to encrypt data keys: bson_t kms_providers; { char *as_json = bson_strdup_printf(BSON_STR({"local" : {"key" : "%s"}}), local_key); init_bson(kms_providers, as_json); bson_free(as_json); } // Create client configured to automatically decrypt: mongoc_client_t *client; { client = mongoc_client_new(uri); if (!client) { FAIL("Failed to create client"); } mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new(); // Bypass automatic encryption (requires mongocryptd/crypt_shared) but keep automatic decryption: mongoc_auto_encryption_opts_set_bypass_auto_encryption(ae_opts, true); mongoc_auto_encryption_opts_set_keyvault_namespace(ae_opts, keyvault_db_name, keyvault_coll_name); mongoc_auto_encryption_opts_set_kms_providers(ae_opts, &kms_providers); if (!mongoc_client_enable_auto_encryption(client, ae_opts, &error)) { FAIL("Failed to enable auto encryption: %s", error.message); } mongoc_auto_encryption_opts_destroy(ae_opts); } // Set up key vault collection: { mongoc_collection_t *coll = mongoc_client_get_collection(client, keyvault_db_name, keyvault_coll_name); mongoc_collection_drop(coll, NULL); // Clear pre-existing data. // Create index to ensure keys have unique keyAltNames: bson_t index_keys, index_opts; init_bson(index_keys, BSON_STR({"keyAltNames" : 1})); init_bson(index_opts, BSON_STR({"unique" : true, "partialFilterExpression" : {"keyAltNames" : {"$exists" : true}}})); mongoc_index_model_t *index_model = mongoc_index_model_new(&index_keys, &index_opts); if (!mongoc_collection_create_indexes_with_opts( coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to create index: %s", error.message); } mongoc_index_model_destroy(index_model); bson_destroy(&index_opts); bson_destroy(&index_keys); mongoc_collection_destroy(coll); } // Create ClientEncryption object: mongoc_client_encryption_t *client_encryption; { mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new(); mongoc_client_encryption_opts_set_kms_providers(ce_opts, &kms_providers); mongoc_client_encryption_opts_set_keyvault_namespace(ce_opts, keyvault_db_name, keyvault_coll_name); mongoc_client_encryption_opts_set_keyvault_client(ce_opts, client); client_encryption = mongoc_client_encryption_new(ce_opts, &error); if (!client_encryption) { FAIL("Failed to create ClientEncryption: %s", error.message); } mongoc_client_encryption_opts_destroy(ce_opts); } // Create data key (see: // https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules): bson_value_t datakey_id; { mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new(); if (!mongoc_client_encryption_create_datakey(client_encryption, "local", dk_opts, &datakey_id, &error)) { FAIL("Failed to create data key: %s", error.message); } mongoc_client_encryption_datakey_opts_destroy(dk_opts); } // Explicitly encrypt a value: bson_value_t encrypted_value; { mongoc_client_encryption_encrypt_opts_t *e_opts = mongoc_client_encryption_encrypt_opts_new(); mongoc_client_encryption_encrypt_opts_set_algorithm(e_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC); mongoc_client_encryption_encrypt_opts_set_keyid(e_opts, &datakey_id); bson_value_t to_encrypt = {.value_type = BSON_TYPE_INT32, .value = {.v_int32 = 123}}; if (!mongoc_client_encryption_encrypt(client_encryption, &to_encrypt, e_opts, &encrypted_value, &error)) { FAIL("Failed to encrypt field: %s", error.message); } mongoc_client_encryption_encrypt_opts_destroy(e_opts); } // Insert document with encrypted payload: mongoc_collection_t *encrypted_coll = mongoc_client_get_collection(client, encrypted_db_name, encrypted_coll_name); { mongoc_collection_drop(encrypted_coll, NULL); // Clear pre-existing data. bson_t to_insert = BSON_INITIALIZER; BSON_APPEND_VALUE(&to_insert, "encryptedField", &encrypted_value); if (!mongoc_collection_insert_one(encrypted_coll, &to_insert, NULL /* opts */, NULL /* reply */, &error)) { FAIL("Failed to insert: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(&to_insert, NULL); printf("Inserted document with encrypted payload: %s\n", as_str); bson_free(as_str); bson_destroy(&to_insert); } // Retrieve document (automatically decrypts): { bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(encrypted_coll, &filter, NULL, NULL); const bson_t *result; if (!mongoc_cursor_next(cursor, &result)) { FAIL("Failed to find inserted document: %s", error.message); } char *as_str = bson_as_relaxed_extended_json(result, NULL); printf("Retrieved document with automatic decryption: %s\n", as_str); bson_free(as_str); mongoc_cursor_destroy(cursor); bson_destroy(&filter); } mongoc_collection_destroy(encrypted_coll); bson_value_destroy(&encrypted_value); bson_value_destroy(&datakey_id); mongoc_client_encryption_destroy(client_encryption); bson_destroy(&kms_providers); mongoc_client_destroy(client); mongoc_cleanup(); return 0; }
可查询加密
可查询加密是下一代正在使用的加密功能,首先在 MongoDB Server 6.0 版中作为预览功能引入,然后在 MongoDB 7.0 中作为普遍可用 (GA) 功能引入。可查询加密支持在加密字段中搜索是否相等,并对每个值进行唯一加密。
注意
QE 需要MongoDB Server 7.0 或更高版本
有关 MongoDB Server 部署从 6.0 升级到 7.0 的信息,请参阅 MongoDB Server 手册中的 将升级 6.0 到 7.0。
有关该功能的更多信息,请参阅MongoDB Server手册中的Queryable Encryption指南。
MongoDB Server 6.0 中的 QE
MongoDB Server 6.0 引入了 Queryable Encryption 作为公共技术预览版。MongoDB Server 7.0 包含对Queryable Encryption协议的向后不兼容的破坏性变更,这些变更会影响不同版本的驱动程序库和服务器之间的兼容性。
下表显示了哪些版本与Queryable Encryption兼容:
libmongocrypt | libmongoc | 兼容的MongoDB Server版本 |
|---|---|---|
1.7.x 及更早版本 | 1.23.x 及更早版本 | 仅限 6.0 |
1.8.0 及更高版本 | 1.24.0 及更高版本 | 7.0及更高版本 |
重要
版本不匹配错误
使用上表所列包的不兼容版本会导致服务器错误。