Overview
在本指南中,您可以学习;了解如何创建使用 Doctrine MongoDB ODM 的 Symfony应用程序来实现MongoDB 的 Queryable Encryption 功能。
Queryable Encryption允许您自动加密和解密文档字段。您可以使用Queryable Encryption来加密应用程序中的敏感数据,将数据字段作为随机加密数据存储在服务器上,并查询加密字段。本教程向您展示如何使用 Doctrine MongoDB ODM设立Queryable Encryption ,Doctrine MongoDB ODM 为PHP应用程序提供对象文档映射器 (ODM)。
提示
To learn more about integrating Symfony and Doctrine with the MongoDB PHP Library, see the Symfony MongoDB Integration tutorial.
先决条件
在开始本教程之前,请完成以下先决任务:
Create a MongoDB Atlas account and configure a cluster. Ensure that your cluster runs on MongoDB Server version 7.0 or later. To learn more, see the MongoDB Get Started guide.
Download the Automatic Encryption Shared Library. To view instructions, see the Install and Configure a Query Analysis Component guide.
下载PHP扩展。要学习;了解更多信息,请参阅扩展文档中的安装。
安装PHP 8.1 或更高版本。
安装 Composer 2.0 或更高版本。
安装 Symfony CLI。要学习;了解更多信息,请参阅 Symfony CLI 文档。
Tutorial
本教程介绍如何创建使用 Symfony 和 Doctrine MongoDB ODM 的Queryable Encryption应用程序。该应用程序对患者病历进行加密和解密,并查询加密的医疗数据。
设置您的项目
按照本节中的步骤安装项目依赖项、配置环境并创建应用程序结构。
设置您的环境。
在终端中运行以下命令以创建新的 Symfony应用程序并安装必要的依赖项:
symfony new qe-symfony-app cd qe-symfony-app composer require doctrine/mongodb-odm-bundle mongodb/mongodb
这些命令创建 qe-symfony-app项目目录并安装以下依赖项:
Doctrine MongoDB ODM Bundle,Doctrine MongoDB ODM 的 Symfony 集成
MongoDB PHP库,即适用于PHP的官方MongoDB驱动程序
定义文档类。
本教程使用 Patient、PatientRecord 和 Billing 类来表示患者医疗记录。
将以下代码粘贴到src/Document/Patient.php文件:
namespace App\Document; use Doctrine\ODM\MongoDB\Mapping\Attribute as ODM; #[ODM\Document(collection: 'patients')] class Patient { #[ODM\Id] public string $id; #[ODM\Field] public string $patientName; #[ODM\Field] public int $patientId; #[ODM\EmbedOne(targetDocument: PatientRecord::class)] public PatientRecord $patientRecord; }
然后,将以下代码粘贴到 src/Document/PatientRecord.php文件中:
namespace App\Document; use Doctrine\ODM\MongoDB\Mapping\Attribute as ODM; use Doctrine\ODM\MongoDB\Mapping\EncryptQuery; #[ODM\EmbeddedDocument] class PatientRecord { #[ODM\Field] #[ODM\Encrypt(queryType: EncryptQuery::Equality)] public string $ssn; #[ODM\EmbedOne(targetDocument: Billing::class)] #[ODM\Encrypt] public Billing $billing; #[ODM\Field] public int $billAmount; }
最后,将以下代码粘贴到 src/Document/Billing.php文件中:
namespace App\Document; use Doctrine\ODM\MongoDB\Mapping\Attribute as ODM; #[ODM\EmbeddedDocument] class Billing { #[ODM\Field] public string $type; #[ODM\Field] public string $number; }
文档类定义了 patients集合中文档的结构。PatientRecord 类包含用于指定以下加密字段的 #[ODM\Encrypt] 属性:
patientRecord.ssn:针对相等查询进行加密和配置patientRecord.billing:已加密,但不可查询
创建控制台命令。
将以下代码粘贴到src/Command/QueryableEncryptionCommand.php文件:
namespace App\Command; use App\Document\Billing; use App\Document\Patient; use App\Document\PatientRecord; use Doctrine\ODM\MongoDB\Configuration; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Mapping\Driver\AttributeDriver; use MongoDB\BSON\Binary; use MongoDB\Client; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; ( name: 'app:queryable-encryption', description: 'Demonstrates Queryable Encryption with ' . 'Doctrine MongoDB ODM', ) class QueryableEncryptionCommand extends Command { protected function execute( InputInterface $input, OutputInterface $output, ): int { // Paste application variables below // Paste encryption credentials below // Paste connection and configuration below // Paste collection setup below // Paste insert operation below // Paste encrypted query below return Command::SUCCESS; } }
本教程的后续步骤将指导您在每个相应的注释下添加代码。
加密并连接到MongoDB
设置项目文件和依赖项后,请按照本节中的步骤配置加密凭证并连接到MongoDB。
分配应用程序变量。
在 src/Command/QueryableEncryptionCommand.php文件中,在 // Paste application variables below 注释下添加以下代码:
// Paste application variables below $keyVaultNamespace = 'encryption.__keyVault'; $encryptedDatabase = 'medicalRecords'; $encryptedCollection = 'patients';
该代码设置以下变量:
keyVaultNamespace - MongoDB中用于存储数据加密密钥 (DEK) 的命名空间。本教程使用
encryption数据库中的__keyVault集合。cryptoDatabase — 存储加密数据的数据库。本教程使用
medicalRecords数据库。cryptoCollection - 存储加密数据的集合。本教程使用
patients集合。
配置您的客户主密钥。
在 // Paste encryption credentials below 注释下添加以下代码:
// Paste encryption credentials below $keyFile = __DIR__ . '/../../master-key.bin'; if (!file_exists($keyFile)) { file_put_contents($keyFile, random_bytes(96)); } $masterKeyBytes = file_get_contents($keyFile); $kmsProvider = [ 'type' => 'local', 'key' => new Binary( $masterKeyBytes, Binary::TYPE_GENERIC, ), ];
此代码创建或加载 96 字节的本地客户主密钥文件。$kmsProvider数组配置用于加密的本地KMS提供商。
警告
本地客户主密钥存储
本教程将您的客户主密钥存储在本地文件中。请勿在生产中使用此方法。如果没有远程KMS,您可能会面临未经授权访问权限加密密钥或丢失解密数据所需密钥的风险。
配置自动加密选项。
直接在上一步的KMS提供商程序配置下添加以下代码:
$autoEncryptionOptions = [ 'keyVaultNamespace' => $keyVaultNamespace, ]; $cryptSharedLibPath = $_ENV['CRYPT_SHARED_LIB_PATH'] ?? ''; if ($cryptSharedLibPath) { $autoEncryptionOptions['extraOptions'] = [ 'cryptSharedLibPath' => $cryptSharedLibPath, ]; }
此代码设置密钥保管库命名空间并配置自动加密共享库的路径。
配置您的 DocumentManager。
在 // Paste connection and configuration below 注释下添加以下代码:
// Paste connection and configuration below $cacheDir = __DIR__ . '/../../var/cache/doctrine'; $config = new Configuration(); $config->setAutoEncryption($autoEncryptionOptions); $config->setKmsProvider($kmsProvider); $config->setProxyDir($cacheDir . '/Proxies'); $config->setProxyNamespace('Proxies'); $config->setHydratorDir($cacheDir . '/Hydrators'); $config->setHydratorNamespace('Hydrators'); $config->setDefaultDB($encryptedDatabase); $config->setMetadataDriverImpl( new AttributeDriver([__DIR__ . '/../Document']) ); $client = new Client( uri: $_ENV['MONGODB_URI'], uriOptions: [], driverOptions: $config->getDriverOptions(), ); $dm = DocumentManager::create($client, $config);
此代码使用加密设置配置 Doctrine Configuration对象,创建传递加密驱动程序选项的MongoDB客户端,并为加密操作初始化 DocumentManager。
创建加密集合。
在 // Paste collection setup below 注释下添加以下代码:
// Paste collection setup below $schemaManager = $dm->getSchemaManager(); $schemaManager->dropDocumentCollection(Patient::class); $schemaManager->createDocumentCollection(Patient::class);
此代码会删除所有现有集合,并使用Queryable Encryption所需的加密元数据创建新的 patients集合。每次调用 createDocumentCollection() 都会为加密字段生成新的数据加密密钥。
执行加密操作
配置应用程序和数据库连接后,请按照本节中的步骤插入和查询加密文档。
插入加密数据。
在 src/Command/QueryableEncryptionCommand.php文件中,在 // Paste insert operation below 注释下添加以下代码:
// Paste insert operation below $billing = new Billing(); $billing->type = 'Visa'; $billing->number = '4111111111111111'; $record = new PatientRecord(); $record->ssn = '987-65-4320'; $record->billing = $billing; $record->billAmount = 1500; $patient = new Patient(); $patient->patientName = 'Jon Doe'; $patient->patientId = 12345678; $patient->patientRecord = $record; $dm->persist($patient); $dm->flush(); $dm->clear(); $output->writeln( 'Successfully inserted the patient document.' );
在将文档存储到MongoDB之前,Queryable Encryption自动加密 patientRecord.ssn 和 patientRecord.billing 字段。
查询加密数据。
在 // Paste encrypted query below 注释下添加以下代码:
// Paste encrypted query below $found = $dm ->getRepository(Patient::class) ->findOneBy(['patientRecord.ssn' => '987-65-4320']); if ($found instanceof Patient) { $output->writeln('Found patient:'); $output->writeln( ' Name: ' . $found->patientName ); $output->writeln( ' SSN: ' . $found->patientRecord->ssn ); $output->writeln( ' Billing type: ' . $found->patientRecord->billing->type ); $output->writeln( ' Billing number: ' . $found->patientRecord->billing->number ); $output->writeln( ' Bill amount: ' . $found->patientRecord->billAmount ); } $output->writeln('Connection closed.');
此代码对加密的patientRecord.ssn字段执行相等查询。
运行您的应用程序。
要启动应用程序,请从 qe-symfony-app项目目录运行以下命令:
php bin/console app:queryable-encryption
如果成功,命令输出将类似于以下示例:
Successfully inserted the patient document. Found patient: Name: Jon Doe SSN: 987-65-4320 Billing type: Visa Billing number: 4111111111111111 Bill amount: 1500 Connection closed.
在数据库中,文档已加密。MongoDB会将标有 #[ODM\Encrypt] 属性的字段存储为BSON二进制数据,并包含用于元数据标签的 __safeContent__字段。存储的文档如下所示:
{ "_id": { "$oid": "..." }, "patientName": "Jon Doe", "patientId": 12345678, "patientRecord": { "ssn": { "$binary": { ... } }, "billing": { "$binary": { ... } }, "billAmount": 1500 }, "__safeContent__": [ { "$binary": { ... } } ] }
后续步骤
恭喜完成 Doctrine ODM Queryable Encryption教程!您现在拥有一个示例Symfony应用程序,它使用Queryable Encryption自动加密和解密文档字段。您的应用程序会在服务器端加密敏感数据,并在客户端查询数据。
要学习;了解有关Queryable Encryption和 Doctrine MongoDB ODM 的更多信息,请访问以下资源:
在MongoDB Server手册中查看更多驱动程序Queryable Encryption教程。
在 Doctrine MongoDB ODM 文档中了解详情有关 Doctrine MongoDB ODM 的更多信息。
Learn more about integrating Doctrine MongoDB ODM with Symfony in the Symfony MongoDB Integration tutorial.