正在使用的加密
Dependencies
要开始在项目中使用正在使用的加密, 扩展 需要使用 libmongocrypt 进行编译 (默认启用)。
此外,需要 crypt_shared
或mongocryptd
才能使用自动客户端加密。 显式加密不需要这两种方法。
crypt_shared
自动加密共享库( crypt_shared
) 提供与mongocryptd
相同的功能,但不要求您生成另一个进程来执行自动加密。
默认,该扩展会尝试从系统路径加载crypt_shared
,如果找到,则会自动使用它。 要从其他位置加载 ,请使用 自动加密crypt_shared
cryptSharedLibPath
驾驶员选项 构建客户端时。如果扩展无法加载crypt_shared
,它将尝试默认使用mongocryptd
。 cryptSharedLibRequired
选项可用于始终需要crypt_shared
,并在无法加载时失败。
有关详细的安装说明,请参阅自动加密共享库的 MongoDB 文档。
mongocryptd
mongocryptd
二进制文件是自动客户端加密的替代要求,并作为组件包含在MongoDB Enterprise MongoDB Server包中。 有关详细的安装说明,请参阅有关 mongocryptd 的 MongoDB 文档。
mongocryptd
执行以下操作:
解析客户端配置中指定的自动加密规则。 如果
schemaMap
自动加密驱动程序选项包含无效语法,mongocryptd
将返回错误。使用指定的自动加密规则对读写操作中的字段进行标记,以便加密。
拒绝在应用于加密字段时可能返回意外或不正确结果的读/写操作。 有关支持和不支持的操作,请参阅自动加密支持的操作。
配置自动加密的客户端将自动从应用程序的PATH
生成mongocryptd
进程。 应用程序可以通过各种自动加密 驱动程序选项来控制生成行为。
mongocryptd
仅负责支持自动客户端加密,本身不执行任何加密或解密。
管理加密密钥
提示
创建加密密钥
注意
以下示例使用本地主密钥。 虽然这适用于开发,但生产应用程序应使用受支持的云提供商(例如 Amazon Web Services KMS )。 主密钥用于加密本地存储的数据密钥,因此确保该密钥的安全非常重要。
要创建加密密钥,请使用加密选项创建一个 MongoDB\Driver\ClientEncryption 实例,并使用 createDataKey() 方法。该方法将返回密钥 ID,稍后可以使用此密钥 ID 引用密钥。您还可以为此密钥传递多个备用名称,并通过这些名称而不是密钥 ID 来引用此密钥。
创建新的数据加密密钥通常在初始部署时完成,但根据您的使用案例,您可能希望使用多个加密密钥(例如 用户特定的加密密钥)或动态创建密钥。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); /* Prepare the database for this script. Drop the key vault collection and * ensure it has a unique index for keyAltNames. This would typically be done * during application deployment. */ $client->getCollection('encryption', '__keyVault')->drop(); $client->getCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], [ 'unique' => true, 'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]], ]); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], ]); /* Create a data encryption key. To store the key ID for later use, you can use * serialize(), var_export(), etc. */ $keyId = $clientEncryption->createDataKey('local'); print_r($keyId); // Encrypt a value using the key that was just created $encryptedValue = $clientEncryption->encrypt('mySecret', [ 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId, ]); print_r($encryptedValue);
通过备用名称引用加密密钥
要引用应用程序中的密钥,可以使用创建密钥时指定的keyAltName
属性。 以下示例创建具有备用名称的加密密钥,这可以在部署应用程序时完成。 然后,该脚本使用keyAltName
选项而不是keyId
按密钥的替代名称引用密钥,从而加密数据。
注意
在添加新的密钥备用名称之前,必须在keyAltNames
字段上创建部分唯一索引。 客户端字段级加密取决于服务器强制执行的密钥备用名称的唯一性。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Exception\ServerException; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); /* Prepare the database for this script. Drop the key vault collection and * ensure it has a unique index for keyAltNames. This would typically be done * during application deployment. */ $client->getCollection('encryption', '__keyVault')->drop(); $client->getCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], [ 'unique' => true, 'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]], ]); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], ]); // Create a data encryption key with an alternate name $clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]); /* Attempt to create a second key with the same name to demonstrate that the * unique index is enforced. */ try { $clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]); } catch (ServerException $e) { printf("Error creating key: %s\n", $e->getMessage()); } // Encrypt a value, using the "keyAltName" option instead of "keyId" $encryptedValue = $clientEncryption->encrypt('mySecret', [ 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyAltName' => 'myDataKey', ]); print_r($encryptedValue);
客户端字段级加密 (Client-Side Field Level Encryption)
除了静态加密和 TLS/SSL(传输加密)等现有MongoDB加密功能之外,客户端字段级加密还允许应用程序加密特定数据字段。
通过字段级加密,应用程序可以在通过线路将数据传输到服务器之前对文档中的字段进行加密。 客户端字段级加密支持的工作负载中,应用程序必须保证包括服务器管理员在内的未经授权方无法读取加密数据。
自动客户端字段级加密
注意
要使用客户端字段级自动加密功能,您必须连接运行MongoDB 6.0 或更高版本的 Enterprise 或Atlas 集群。
通过创建客户端并指定autoEncryption
驱动程序选项 ,启用客户端字段级自动加密 。以下示例演示了如何设置自动客户端字段级加密并使用 MongoDB\Driver\ClientEncryption 对象来创建新的加密密钥。
服务器端字段级加密实施
您可以使用模式验证来实施对集合中的特定字段加密。此模式验证将防止应用程序为任何标有“加密”模式关键字的字段插入未加密的值。
以下示例使用$jsonSchema
验证器和加密模式语法设置具有自动加密功能的集合。 encryptedField
字段中的数据在插入时自动加密,在客户端读取时自动解密。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Exception\ServerException; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; /* Note: this script assumes that the test database is empty and that the key * vault collection exists and has a partial, unique index on keyAltNames (as * demonstrated in the encryption key management scripts). */ // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], ]); /* Create a data encryption key. Alternatively, this key ID could be read from a * configuration file. */ $keyId = $clientEncryption->createDataKey('local'); // Create another client with automatic encryption enabled $encryptedClient = new Client($uri, [], [ 'autoEncryption' => [ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], ], ]); // Define a JSON schema for the encrypted collection $schema = [ 'bsonType' => 'object', 'properties' => [ 'encryptedField' => [ 'encrypt' => [ 'keyId' => [$keyId], 'bsonType' => 'string', 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, ], ], ], ]; /* Create a new collection for this script. Configure a server-side schema by * explicitly creating the collection with a "validator" option. */ $encryptedClient->getDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); $encryptedCollection = $encryptedClient->getCollection('test', 'coll'); /* Using the encrypted client, insert and find a document to demonstrate that * the encrypted field is automatically encrypted and decrypted. */ $encryptedCollection->insertOne(['_id' => 1, 'encryptedField' => 'mySecret']); print_r($encryptedCollection->findOne(['_id' => 1])); /* Using the client configured without encryption, find the same document and * observe that the field is not automatically decrypted. */ $unencryptedCollection = $client->getCollection('test', 'coll'); print_r($unencryptedCollection->findOne(['_id' => 1])); /* Attempt to insert another document with an unencrypted field value to * demonstrate that the server-side schema is enforced. */ try { $unencryptedCollection->insertOne(['_id' => 2, 'encryptedField' => 'myOtherSecret']); } catch (ServerException $e) { printf("Error inserting document: %s\n", $e->getMessage()); }
提供本地自动加密规则
以下示例使用schemaMap
自动加密驱动程序选项,并使用JSON schema语法的严格子集来定义加密字段。
与完全依赖从服务器获取的模式相比,将 schemaMap
与服务器端模式结合使用可提供更高的安全性。它可以防止恶意服务器宣传虚假模式,虚假模式可能会诱使客户端发送应当加密的未加密数据。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Exception\ServerException; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; /* Note: this script assumes that the test database is empty and that the key * vault collection exists and has a partial, unique index on keyAltNames (as * demonstrated in the encryption key management scripts). */ // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], ]); /* Create a data encryption key. Alternatively, this key ID could be read from a * configuration file. */ $keyId = $clientEncryption->createDataKey('local'); /* Define a JSON schema for the encrypted collection. Since this only utilizes * encryption schema syntax, it can be used for both the server-side and local * schema. */ $schema = [ 'bsonType' => 'object', 'properties' => [ 'encryptedField' => [ 'encrypt' => [ 'keyId' => [$keyId], 'bsonType' => 'string', 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, ], ], ], ]; /* Create another client with automatic encryption enabled. Configure a local * schema for the encrypted collection using the "schemaMap" option. */ $encryptedClient = new Client($uri, [], [ 'autoEncryption' => [ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], 'schemaMap' => ['test.coll' => $schema], ], ]); /* Create a new collection for this script. Configure a server-side schema by * explicitly creating the collection with a "validator" option. * * Note: without a server-side schema, another client could potentially insert * unencrypted data into the collection. Therefore, a local schema should always * be used in conjunction with a server-side schema. */ $encryptedClient->getDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); $encryptedCollection = $encryptedClient->getCollection('test', 'coll'); /* Using the encrypted client, insert and find a document to demonstrate that * the encrypted field is automatically encrypted and decrypted. */ $encryptedCollection->insertOne(['_id' => 1, 'encryptedField' => 'mySecret']); print_r($encryptedCollection->findOne(['_id' => 1])); /* Using the client configured without encryption, find the same document and * observe that the field is not automatically decrypted. */ $unencryptedCollection = $client->getCollection('test', 'coll'); print_r($unencryptedCollection->findOne(['_id' => 1])); /* Attempt to insert another document with an unencrypted field value to * demonstrate that the server-side schema is enforced. */ try { $unencryptedCollection->insertOne(['_id' => 2, 'encryptedField' => 'myOtherSecret']); } catch (ServerException $e) { printf("Error inserting document: %s\n", $e->getMessage()); }
显式加密
显式加密是MongoDB Community的一项功能,不使用 crypt_shared
或 mongocryptd
。 显式加密由 MongoDB\Driver\ClientEncryption 类。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; /* Note: this script assumes that the test database is empty and that the key * vault collection exists and has a partial, unique index on keyAltNames (as * demonstrated in the encryption key management scripts). */ // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], ]); /* Create a data encryption key. Alternatively, this key ID could be read from a * configuration file. */ $keyId = $clientEncryption->createDataKey('local'); // Insert a document with a manually encrypted field $encryptedValue = $clientEncryption->encrypt('mySecret', [ 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId, ]); $collection = $client->getCollection('test', 'coll'); $collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]); /* Using the client configured without encryption, find the document and observe * that the field is not automatically decrypted. */ /** @var object{encryptedField: Binary} $document */ $document = $collection->findOne(); print_r($document); // Manually decrypt the field printf("Decrypted: %s\n", $clientEncryption->decrypt($document->encryptedField));
带自动解密的显式加密
所有用户都支持自动解密。要配置自动解密而不自动加密,请在构建客户端时设立bypassAutoEncryption
自动加密驾驶员选项。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; /* Note: this script assumes that the test database is empty and that the key * vault collection exists and has a partial, unique index on keyAltNames (as * demonstrated in the encryption key management scripts). */ // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with automatic encryption disabled $client = new Client($uri, [], [ 'autoEncryption' => [ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], 'bypassAutoEncryption' => true, ], ]); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], ]); /* Create a data encryption key. Alternatively, this key ID could be read from a * configuration file. */ $keyId = $clientEncryption->createDataKey('local'); // Insert a document with a manually encrypted field $encryptedValue = $clientEncryption->encrypt('mySecret', [ 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId, ]); $collection = $client->getCollection('test', 'coll'); $collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]); /* Using the client configured with encryption (but not automatic encryption), * find the document and observe that the field is automatically decrypted. */ $document = $collection->findOne(); print_r($document);
可查询加密
在 MongoDB 7.0中引入, 可Queryable Encryption是另一种正在使用的加密形式。 数据在客户端加密。 可Queryable Encryption支持索引加密字段,这些字段会在服务器端进行进一步处理。
自动 Queryable Encryption
注意
自动Queryable Encryption需要MongoDB 7.0+ Enterprise 或 MongoDB 7.0 + Atlas 集群。
可查询加密中的自动Queryable Encryption利用 crypt_shared
或 mongocryptd
在客户端自动加密和解密数据。 encryptedIndexed
和encryptedUnindexed
字段中的数据将在插入时自动加密,并在客户端查询时自动解密。 此外,还可以对encryptedIndexed
字段进行查询。
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; /* Note: this script assumes that the test database is empty and that the key * vault collection exists and has a partial, unique index on keyAltNames (as * demonstrated in the encryption key management scripts). */ // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], ]); /* Create the data encryption keys for this script. Alternatively, the key IDs * could be read from a configuration file. */ $keyId1 = $clientEncryption->createDataKey('local'); $keyId2 = $clientEncryption->createDataKey('local'); /* Create another client with automatic encryption enabled. Configure the * encrypted collection using the "encryptedFields" option. */ $encryptedClient = new Client($uri, [], [ 'autoEncryption' => [ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], 'encryptedFieldsMap' => [ 'test.coll' => [ 'fields' => [ [ 'path' => 'encryptedIndexed', 'bsonType' => 'string', 'keyId' => $keyId1, 'queries' => ['queryType' => ClientEncryption::QUERY_TYPE_EQUALITY], ], [ 'path' => 'encryptedUnindexed', 'bsonType' => 'string', 'keyId' => $keyId2, ], ], ], ], ], ]); /* Create the data collection for this script. The create and drop helpers will * infer encryptedFields from the client configuration and manage internal * encryption collections automatically. Alternatively, the "encryptedFields" * option can also be passed explicitly. */ $encryptedClient->getDatabase('test')->createCollection('coll'); $encryptedCollection = $encryptedClient->getCollection('test', 'coll'); /* Using the encrypted client, insert a document and find it by querying on the * encrypted field. Fields will be automatically encrypted and decrypted. */ $encryptedCollection->insertOne([ '_id' => 1, 'encryptedIndexed' => 'indexedValue', 'encryptedUnindexed' => 'unindexedValue', ]); print_r($encryptedCollection->findOne(['encryptedIndexed' => 'indexedValue'])); /* Using the client configured without encryption, find the same document and * observe that fields are not automatically decrypted. */ $unencryptedCollection = $client->getCollection('test', 'coll'); print_r($unencryptedCollection->findOne(['_id' => 1]));
显式Queryable Encryption
注意
显式Queryable Encryption需要MongoDB 7.0+。
Queryable Encryption可查询加密中的显式 是使用MongoDB \Driver\ClientEncryption::encrypt() 和 解密() 方法。尽管值必须显式加密(例如 插入、查询条件),可以通过在集合上配置encryptedFields
来自动解密查询,如以下示例所示:
use MongoDB\BSON\Binary; use MongoDB\Client; use MongoDB\Driver\ClientEncryption; require __DIR__ . '/../../../vendor/autoload.php'; $uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; /* Note: this script assumes that the test database is empty and that the key * vault collection exists and has a partial, unique index on keyAltNames (as * demonstrated in the encryption key management scripts). */ // Generate a secure local key to use for this script $localKey = new Binary(random_bytes(96)); // Create a client with no encryption options $client = new Client($uri); // Create a ClientEncryption object to manage data encryption keys $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], ]); /* Create the data encryption keys. Alternatively, the key IDs could be read * from a configuration file. */ $keyId1 = $clientEncryption->createDataKey('local'); $keyId2 = $clientEncryption->createDataKey('local'); // Create another client with automatic encryption disabled $encryptedClient = new Client($uri, [], [ 'autoEncryption' => [ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => ['local' => ['key' => $localKey]], 'bypassQueryAnalysis' => true, ], ]); // Define encrypted fields for the collection $encryptedFields = [ 'fields' => [ [ 'path' => 'encryptedIndexed', 'bsonType' => 'string', 'keyId' => $keyId1, 'queries' => ['queryType' => ClientEncryption::QUERY_TYPE_EQUALITY], ], [ 'path' => 'encryptedUnindexed', 'bsonType' => 'string', 'keyId' => $keyId2, ], ], ]; /* Create the data collection for this script. Specify the "encryptedFields" * option to ensure that internal encryption collections are also created. The * "encryptedFields" option should also be specified when dropping the * collection to ensure that internal encryption collections are dropped. */ $encryptedClient->getDatabase('test')->createCollection('coll', ['encryptedFields' => $encryptedFields]); $encryptedCollection = $encryptedClient->getCollection('test', 'coll'); // Insert a document with manually encrypted fields $indexedInsertPayload = $clientEncryption->encrypt('indexedValue', [ 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, 'contentionFactor' => 1, 'keyId' => $keyId1, ]); $unindexedInsertPayload = $clientEncryption->encrypt('unindexedValue', [ 'algorithm' => ClientEncryption::ALGORITHM_UNINDEXED, 'keyId' => $keyId2, ]); $encryptedCollection->insertOne([ '_id' => 1, 'encryptedIndexed' => $indexedInsertPayload, 'encryptedUnindexed' => $unindexedInsertPayload, ]); /* Encrypt the payload for an "equality" query using the same key that was used * to encrypt the corresponding insert payload. */ $indexedFindPayload = $clientEncryption->encrypt('indexedValue', [ 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, 'queryType' => ClientEncryption::QUERY_TYPE_EQUALITY, 'contentionFactor' => 1, 'keyId' => $keyId1, ]); /* Using the client configured with encryption (but not automatic encryption), * find the document and observe that the fields are automatically decrypted. */ print_r($encryptedCollection->findOne(['encryptedIndexed' => $indexedFindPayload]));