对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

Queryable Encryption 使用 Symfony 和 Doctrine ODM

在本指南中,您可以学习;了解如何创建使用 Doctrine MongoDB ODM 的 Symfony应用程序来实现MongoDB 的 Queryable Encryption 功能。

Queryable Encryption允许您自动加密和解密文档字段。您可以使用Queryable Encryption来加密应用程序中的敏感数据,将数据字段作为随机加密数据存储在服务器上,并查询加密字段。本教程向您展示如何使用 Doctrine MongoDB ODM设立Queryable Encryption ,Doctrine MongoDB ODM 为PHP应用程序提供对象文档映射器 (ODM)。

提示

要学习;了解有关将 Symfony 和 Doctrine 与 MongoDB PHP 库集成的更多信息,请参阅 Symfony MongoDB 集成 教程。

在开始本教程之前,请完成以下先决任务:

  • 创建MongoDB Atlas帐户并配置集群。确保您的集群在MongoDB Server 7.0 或更高版本上运行。要学习;了解更多信息,请参阅MongoDB入门指南。

  • 下载自动加密共享库。要查看说明,请参阅《安装和配置查询分析组件》指南。

  • 下载PHP扩展。要学习;了解更多信息,请参阅扩展文档中的安装。

  • 安装PHP 8.1 或更高版本。

  • 安装 Composer 2.0 或更高版本。

  • 安装 Symfony CLI。要学习;了解更多信息,请参阅 Symfony CLI 文档。

本教程介绍如何创建使用 Symfony 和 Doctrine MongoDB ODM 的Queryable Encryption应用程序。该应用程序对患者病历进行加密和解密,并查询加密的医疗数据。

按照本节中的步骤安装项目依赖项、配置环境并创建应用程序结构。

1

在终端中运行以下命令以创建新的 Symfony应用程序并安装必要的依赖项:

symfony new qe-symfony-appcd qe-symfony-appcomposer require doctrine/mongodb-odm-bundle mongodb/mongodb

这些命令创建 qe-symfony-app项目目录并安装以下依赖项:

2

在项目目录中,打开 .env文件并添加或修改以下变量:

MONGODB_URI=<connection URI>CRYPT_SHARED_LIB_PATH=<Automatic Encryption Shared Library path>

将 <connection URI> 占位符替换为连接到集群的连接 URI,并将 <Automatic Encryption Shared Library path> 替换为自动加密共享库的完整路径。确保该路径指向下载的包中的 lib/mongo_crypt_v1.dylib。

3

在项目的 src/目录中,创建以下子目录和文件以定义文档结构和应用程序逻辑:

  • src/Document/Patient.php

  • src/Document/PatientRecord.php

  • src/Document/Billing.php

  • src/Command/QueryableEncryptionCommand.php

本教程的后续步骤将指导您向每个文件添加代码。

4

本教程使用 Patient、PatientRecord 和 Billing 类来表示患者医疗记录。

将以下代码粘贴到src/Document/Patient.php文件:

src/Document/Patient.php

<?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文件中:

src/Document/PatientRecord.php

<?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文件中:

src/Document/Billing.php

<?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:已加密,但不可查询

5

将以下代码粘贴到src/Command/QueryableEncryptionCommand.php文件:

<?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; #[AsCommand( 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。

1

在 src/Command/QueryableEncryptionCommand.php文件中,在 // Paste application variables below 注释下添加以下代码:

src/Command/QueryableEncryptionCommand.php

// Paste application variables below$keyVaultNamespace = 'encryption.__keyVault';$encryptedDatabase = 'medicalRecords';$encryptedCollection = 'patients';

该代码设置以下变量:

  • keyVaultNamespace - MongoDB中用于存储数据加密密钥 (DEK) 的命名空间。本教程使用 encryption数据库中的 __keyVault集合。

  • cryptoDatabase — 存储加密数据的数据库。本教程使用 medicalRecords数据库。

  • cryptoCollection - 存储加密数据的集合。本教程使用 patients集合。

2

在 // Paste encryption credentials below 注释下添加以下代码:

src/Command/QueryableEncryptionCommand.php

// Paste encryption credentials below// Warning: Local key files are for development only. Use a remote KMS in production.$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 的更多信息,请参阅“密钥管理”维基百科条目。

3

直接在上一步的KMS提供商程序配置下添加以下代码:

src/Command/QueryableEncryptionCommand.php

$autoEncryptionOptions = [ 'keyVaultNamespace' => $keyVaultNamespace,]; $cryptSharedLibPath = $_ENV['CRYPT_SHARED_LIB_PATH'] ?? '';if ($cryptSharedLibPath) { $autoEncryptionOptions['extraOptions'] = [ 'cryptSharedLibPath' => $cryptSharedLibPath, ];}

此代码设置密钥保管库命名空间并配置自动加密共享库的路径。

4

在 // Paste connection and configuration below 注释下添加以下代码:

src/Command/QueryableEncryptionCommand.php

// 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。

5

在 // Paste collection setup below 注释下添加以下代码:

src/Command/QueryableEncryptionCommand.php

// Paste collection setup below$schemaManager = $dm->getSchemaManager();$schemaManager->dropDocumentCollection(Patient::class);$schemaManager->createDocumentCollection(Patient::class);

此代码会删除所有现有集合,并使用Queryable Encryption所需的加密元数据创建新的 patients集合。每次调用 createDocumentCollection() 都会为加密字段生成新的数据加密密钥。

配置应用程序和数据库连接后,请按照本节中的步骤插入和查询加密文档。

1

在 src/Command/QueryableEncryptionCommand.php文件中,在 // Paste insert operation below 注释下添加以下代码:

src/Command/QueryableEncryptionCommand.php

// 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 字段。

2

在 // Paste encrypted query below 注释下添加以下代码:

src/Command/QueryableEncryptionCommand.php

// 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字段执行相等查询。

3

要启动应用程序,请从 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: 1500Connection 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 的更多信息,请访问以下资源: