

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 可搜索的加密
<a name="searchable-encryption"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

可搜索加密使您无需解密整个数据库即可搜索加密的记录。该操作使用*信标*完成，信标在写入字段的明文值和实际存储在数据库中的加密值之间创建映射。 AWS 数据库加密 SDK 将信标存储在添加到记录中的新字段中。根据您使用的信标类型，您可以对加密的数据执行完全匹配搜索或更为自定义的复杂查询。

**注意**  
 AWS 数据库加密 SDK 中的可搜索加密不同于学术研究中定义的可搜索对称加密，例如可[搜索](https://dl.acm.org/doi/10.1145/1180405.1180417)的对称加密。



信标是一种截断的 Hash-Based 消息身份验证码 (HMAC) 标签，它将纯文本字段值映射到加密的可搜索标识符。当您向配置为可搜索加密的加密字段写入值时， AWS 数据库加密 SDK 会根据纯文本值计算 HMAC。此 HMAC 输出与该字段的明文值进行一对一（1:1）匹配。SDK 故意截断 HMAC 输出，使多个不同的纯文本值在同一个信标上发生碰撞。这些冲突（误报）限制了未经授权的用户从频率模式中推断出敏感信息的能力。当您查询信标时， AWS 数据库加密 SDK 会自动过滤掉这些误报，并返回查询的纯文本结果。为了进一步解决频率泄漏问题，对信标进行了分区，允许相同的纯文本值在分区之间生成不同的信标值。当表仅使用单个分区时，这种行为自然会与传统的非分区信标相匹配。

每个信标的平均误报数取决于截断后的剩余信标长度和分区数。如需帮助确定适合您的实现的信标长度，请参阅[确定信标长度](choosing-beacon-length.md)。

**注意**  
可搜索加密旨在在未填充的新数据库中实现。在现有数据库中配置的任何信标都只能映射上传到数据库的新记录，信标无法映射现有的数据。

**主题**
+ [信标是否适合我的数据集？](#are-beacons-right-for-me)
+ [可搜索的加密场景](#beacon-overview-example)

## 信标是否适合我的数据集？
<a name="are-beacons-right-for-me"></a>

使用信标对加密的数据执行查询会降低与客户端加密数据库相关的性能成本。当您使用信标时，查询的效率和泄露的有关数据分布的信息量之间存在内在权衡。信标不会更改字段的加密状态。使用 AWS 数据库加密 SDK 对字段进行加密和签名时，该字段的纯文本值永远不会暴露给数据库。数据库将存储字段的随机加密值。

信标存储在[计算信标所依据的加密字段](plan-searchable-encryption.md#plan-searchable-encryption.title)旁边。这意味着，即使未经授权的用户无法查看加密字段的明文值，他们也可以对信标进行统计分析，以了解有关数据集分布的更多信息，并在极端情况下识别信标映射到的明文值。正确的信标配置对于降低这些风险至关重要。选择适当的信标长度和分区方案可以确保足够的碰撞，并通过限制任何单个信标中的值集中来缓解基于频率的攻击，从而保护机密性。

**安全与性能**
+ 更短的信标长度和更高的分区数通过增加碰撞和减少频率泄漏来提高安全性，
+ 更长的信标长度和更少的分区可减少误报和查询扇出，从而提高性能。

在许多实际场景中，精心选择的配置可以平衡这些相互竞争的目标。但是，可搜索的加密可能无法为每个数据集提供所需的安全性和性能级别。

在配置任何信标之前，请仔细检查您的威胁模型、安全要求和性能需求，并考虑数据集的独特性特征，以确定可搜索加密是否是合适的选择。

**分布**  
信标的安全属性既取决于底层数据的分布，也取决于信标的配置方式，包括使用了多少分区。当您将加密字段配置为可搜索加密时， AWS 数据库加密 SDK 会根据写入该字段的每个纯文本值计算 HMAC，并使用加密密钥派生信标。信标是在分区的上下文中计算的，分区允许相同的纯文本值在分区之间生成不同的信标值。当表仅使用单个分区时，相同的纯文本值始终映射到相同的截断的 HMAC 标签，这样可以保留原始数据集中的频率模式。  
分布高度偏斜的字段需要特别注意。例如，考虑一个存储伊利诺伊州所有居民居住城市的数据库。如果您从加密`City`字段构建信标，则值 “芝加哥” 的出现频率将比其他城市高得多。即使未经授权的用户只能访问加密的项目和信标值，这种不平衡也可能使他们能够通过观察代表性过高的信标来推断哪些记录与芝加哥居民相对应。截断信标可以通过强制更多的碰撞来减少这种泄漏，但是由于误报增加，充分隐藏严重偏差所需的信标长度可能会带来显著的性能开销。  
为了安全地配置信标，您应该分析数据的频率分布，并了解截断和分区是如何相互作用的。信标中保留的位数决定了暴露了多少统计信息，而分区的数量限制了任何单个信标值的集中程度。更短的信标长度和更多的分区可以减少频率泄露，但会增加误报和查询扇出。更长的信标长度和更少的分区可以提高查询效率，但会显示更多有关底层分布的信息。  
在某些极端情况下，当表仅使用单个分区时，工作负载不可行。人口非常少或二进制结果高度不平衡的属性（例如以负值为主的医学检查结果）不能仅使用截断来保护。使用一个分区，一个足够短的信标可以隐藏分布，将所有值折叠到一个标签中，而较长的信标则可以轻松识别稀有值。在这些情况下，需要分区信标才能使可搜索的加密变得可行。通过将过度表示的值分布到多个分区，这种方法可以缩小等价类的大小，并以使用单个分区时不可能的方式限制频率泄露。

**相关性**  
强烈建议您避免使用具有相关值的字段构造不同的信标。使用相关字段构造的信标需要更短的信标长度，以充分地最大限度减少向未经授权的用户泄露的有关每个数据集分布的信息量。您必须仔细分析数据集，包括它的熵和相关值的联合分布，以确定需要将信标截断多少。如果产生的信标长度不能满足您的性能需求，则信标可能不适合您的数据集。  
例如，您不应使用 `City` 和 `ZIPCode` 字段构造两个单独的信标，因为邮政编码可能只与一个城市相关联。通常，信标生产生误报会限制未经授权的用户识别有关您的数据集的区分信息的能力。但是 `City` 和 `ZIPCode` 字段之间的关联意味着未经授权的用户可以轻松识别哪些结果是误报，并区分不同的邮政编码。  
您还应避免使用包含相同明文值的字段构造信标。例如，您不应使用 `mobilePhone` 和 `preferredPhone` 字段构造信标，因为它们可能具有相同的值。如果您从两个字段构造不同的信标，则 AWS 数据库加密 SDK 会使用不同的密钥为每个字段创建信标。这会为相同的明文值生成两个不同的 HMAC 标签。这两个不同的信标不太可能产生相同的误报，且未经授权的用户可能能够区分不同的电话号码。

即使您的数据集包含相关字段或具有不均匀的分布，您也可以使用较短的信标长度来构造能够保护数据集机密性的信标。但是，信标长度并不能保证数据集中的每个唯一值都会产生大量误报，从而有效地最大限度减少泄露的有关数据集的区分信息量。信标长度仅能估计产生的误报平均数。数据集分布越不均匀，信标长度在确定产生的误报平均数量方面的有效性就越低。

仔细评估您选择进行信标化的字段的分布，并确定需要多少截断才能满足您的安全要求。本章中的以下主题假设，在每个分区内，信标值均匀分布，并且基础数据不会引入会削弱这些假设的相关性。

## 可搜索的加密场景
<a name="beacon-overview-example"></a>

以下示例演示了一种可搜索的加密解决方案，并说明了本章中讨论的核心概念。在这种情况下，某些字段值非常频繁地出现，如果使用单个分区，则会导致较大的等价类和频率泄漏增加。为了解决这个问题，该配置使用了多个分区，这样可以更均匀地分布高频率的值，从而减少泄漏，同时保留执行高效相等搜索的能力。

以一个名为 `Employees` 的跟踪公司员工数据的数据库为例。*数据库中的每条记录都包含名为 *employeeID *LastName**、*FirstName*、和 “地址” 的字段。*`Employees` 数据库中的每个字段都由主键 `EmployeeID` 标识。

以下是数据库中的明文记录示例。

```
{
    "EmployeeID": 101,
    "LastName": "Jones",
    "FirstName": "Mary",
    "Address": {
                "Street": "123 Main",
                "City": "Anytown",
                "State": "OH",
                "ZIPCode": 12345
    }
}
```

如果您在[加密操作](concepts.md#crypt-actions)中将 `LastName` 和 `FirstName` 字段标记为 `ENCRYPT_AND_SIGN`，则这些字段中的值在上传到数据库之前会在本地进行加密。上传的已加密数据是完全随机的，数据库无法将这些数据识别为受保护。它只检测典型的数据条目。这意味着，实际存储在数据库中的记录可能如下所示。

```
{
    "PersonID": 101,
    "LastName": "1d76e94a2063578637d51371b363c9682bad926cbd",
    "FirstName": "21d6d54b0aaabc411e9f9b34b6d53aa4ef3b0a35",
    "Address": {
                "Street": "123 Main",
                "City": "Anytown",
                "State": "OH",
                "ZIPCode": 12345
    }
}
```

如果您需要在数据库中查询`LastName`字段中的精确匹配项，请[配置一个名为的标准信标](configure-beacons.md#config-standard-beacons)，*LastName*以将写入该`LastName`字段的纯文本值映射到存储在数据库中的加密值。

该信标根据 `LastName` 字段中的明文值计算 HMAC。每个 HMAC 输出都被截断，因此不再与明文值完全匹配。例如，`Jones` 的完整哈希值和截断后的哈希值可能如下所示。

**完整哈希值**

`2aa4e9b404c68182562b6ec761fcca5306de527826a69468885e59dc36d0c3f824bdd44cab45526f70a2a18322000264f5451acf75f9f817e2b35099d408c833`

**截断后的哈希值**

`b35099d408c833`

在包含许多员工的数据集中，某些姓氏（例如*琼斯*、*史密*斯或*约翰逊*）的出现频率可能比其他姓氏高得多。为了减少频率泄漏并限制信标等效类的大小，应将**LastName**信标配置为使用多个分区。

启用分区后，将在写入时将每个项目分配给一个分区，并将分区号合并到信标派生中。因此，姓氏相同的员工可能会跨分区映射到不同的信标值。这会将高频名称分布到多个分区，从而减少任何单个信标值的过度表示。

配置标准信标后，您可以在 `LastName` 字段上执行相等搜索。例如，如果要搜索`Jones`，请使用*LastName*信标执行以下查询。

```
LastName = Jones
```

在查询特定的高频姓氏（例如 **Jones**）时，应用程序应使用**LastName**信标为每个分区发出一个查询。然后， AWS 数据库加密 SDK 对结果进行解密并自动过滤掉所有误报，返回正确的纯文本记录。