

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

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


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

可搜尋加密可讓您在不解密整個資料庫的情況下搜尋加密的記錄。這是使用*信標來完成的*，該信標會在寫入欄位的純文字值與實際存放在資料庫中的加密值之間建立映射。 AWS Database Encryption SDK 會將信標存放在新增至記錄的新欄位中。根據您使用的信標類型，您可以對加密的資料執行完全相符的搜尋或更自訂的複雜查詢。

**注意**  
 AWS 資料庫加密 SDK 中的可搜尋加密與學術研究定義的可搜尋對稱加密不同，例如[可搜尋對稱加密](https://dl.acm.org/doi/10.1145/1180405.1180417)。



信標是截斷的雜湊型訊息驗證碼 (HMAC) 標籤，可在純文字和欄位的加密值之間建立映射。當您將新值寫入設定為可搜尋加密的加密欄位時， AWS 資料庫加密 SDK 會透過純文字值計算 HMAC。此 HMAC 輸出是該欄位純文字值的一對一 (1：1) 比對。HMAC 輸出會截斷，讓多個不同的純文字值對應至相同的截斷 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 加密和簽署欄位時，該欄位的純文字值永遠不會公開給資料庫。資料庫會存放 欄位的隨機加密值。

信標會與其計算來源的加密欄位一起存放。這表示即使未經授權的使用者無法檢視加密欄位的純文字值，他們也可以對信標執行統計分析，以進一步了解資料集的分佈，並在極端情況下識別信標映射到的純文字值。您設定信標的方式可以減輕這些風險。特別是，[選擇正確的信標長度](choosing-beacon-length.md)可協助您保護資料集的機密性。

**安全性與效能**
+ 信標長度越短，保留的安全性就越高。
+ 信標長度越長，保留的效能就越多。

可搜尋加密可能無法為所有資料集提供所需的效能和安全性層級。在設定任何信標之前，請先檢閱您的威脅模型、安全需求和效能需求。

當您判斷可搜尋加密是否適合您的資料集時，請考慮下列資料集唯一性要求。

**分佈**  
信標保留的安全數量取決於資料集的分佈。當您設定可搜尋加密的加密欄位時， AWS 資料庫加密 SDK 會透過寫入該欄位的純文字值來計算 HMAC。針對特定欄位計算的所有信標都是使用相同的金鑰計算，但每個租用戶使用不同金鑰的多租用戶資料庫除外。這表示如果多次將相同的純文字值寫入 欄位，則會針對該純文字值的每個執行個體建立相同的 HMAC 標籤。  
您應該避免從包含非常常見值的欄位建構信標。例如，假設資料庫存放伊利諾州每個居民的地址。如果您從加密`City`欄位建構信標，則由於在芝加哥居住的伊利諾州人口中有很大比例，透過「芝加哥」計算的信標將過度表示。即使未經授權的使用者只能讀取加密的值和信標值，如果信標保留此分佈，他們也可以識別哪些記錄包含芝加哥居民的資料。若要將分佈的辨別資訊量降至最低，您必須充分截斷您的信標。隱藏此不均勻分佈所需的信標長度具有顯著的效能成本，可能不符合應用程式的需求。  
您必須仔細分析資料集的分佈，以確定需要截斷多少信標。截斷後剩餘的信標長度會直接與可辨識分佈的統計資訊量相關。您可能需要選擇較短的信標長度，以充分減少顯示有關資料集的辨別資訊量。  
在極端情況下，您無法計算分佈不均勻資料集的信標長度，以有效地平衡效能和安全性。例如，您不應該從存放罕見疾病醫療測試結果的欄位建構信標。由於預期`NEGATIVE`結果在資料集內會明顯更普遍，因此可以透過結果的罕見程度輕鬆識別`POSITIVE`結果。當 欄位只有兩個可能的值時，隱藏分佈非常困難。如果您使用的信標長度短到足以隱藏分佈，所有純文字值都會對應到相同的 HMAC 標籤。如果您使用較長的信標長度，很明顯哪些信標會映射到純文字`POSITIVE`值。

**關聯性**  
我們強烈建議您避免從具有相關值的欄位建構不同的信標。從相關欄位建構的信標需要較短的信標長度，才能充分將每個資料集分發給未經授權使用者的資訊量降至最低。您必須仔細分析資料集，包括其熵和相關值的關節分佈，以確定需要截斷多少信標。如果產生的信標長度不符合您的效能需求，則信標可能不適合您的資料集。  
例如，您不應該從 `City`和 `ZIPCode` 欄位建構兩個單獨的信標，因為郵遞區號可能只會與一個城市相關聯。一般而言，信標產生的誤報會限制未經授權的使用者識別資料集辨別資訊的能力。但是， `City`和 `ZIPCode` 欄位之間的相互關聯意味著未經授權的使用者可以輕鬆識別哪些結果是誤報，並區分不同的郵遞區號。  
您也應該避免從包含相同純文字值的欄位建構信標。例如，您不應該從 `mobilePhone`和 `preferredPhone` 欄位建構信標，因為它們可能具有相同的值。如果您從這兩個欄位建構不同的信標， AWS 資料庫加密 SDK 會在不同的金鑰下為每個欄位建立信標。這會為相同的純文字值產生兩個不同的 HMAC 標籤。這兩個不同的信標不太可能有相同的誤報，未經授權的使用者可能可以區分不同的電話號碼。

即使您的資料集包含關聯欄位或分佈不均勻，您還是可以建構信標，以使用較短的信標長度來維護資料集的機密性。不過，信標長度不保證資料集中的每個唯一值都會產生許多誤報，以有效地將資料集的辨別資訊量降至最低。信標長度僅估計產生的誤報平均數量。資料集的分佈越不平均，有效信標長度就越低，決定了產生的誤報平均數量。

仔細考慮您建構信標的欄位分佈，並考慮需要多少時間才能截斷信標長度以符合您的安全需求。本章中的下列主題假設您的信標是統一分佈的，且不包含相互關聯的資料。

## 可搜尋的加密案例
<a name="beacon-overview-example"></a>

下列範例示範簡單的可搜尋加密解決方案。在應用程式中，此範例中使用的範例欄位可能不符合信標的分佈和相互關聯唯一性建議。您可以在閱讀本章中的可搜尋加密概念時，使用此範例做為參考。

考慮名為 的資料庫`Employees`，可追蹤公司的員工資料。資料庫中的每個記錄都包含稱為 *EmployeeID*、*LastName*、*FirstName* 和 *Address* 的欄位。`Employees` 資料庫中的每個欄位都由主索引鍵 識別`EmployeeID`。

以下是資料庫中的純文字記錄範例。

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

如果您在[密碼編譯動作](concepts.md#crypt-actions)`ENCRYPT_AND_SIGN`中將 `LastName`和 `FirstName` 欄位標記為 ，則這些欄位中的值會在上傳至資料庫之前在本機加密。上傳的加密資料是完全隨機的，資料庫無法將此資料辨識為受保護。它只會偵測典型的資料項目。這表示實際存放在資料庫中的記錄可能如下所示。

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

如果您需要在 `LastName` 欄位中查詢資料庫的完全相符項目，[請設定名為 LastName 的標準信標](configure-beacons.md#config-standard-beacons)，將寫入`LastName`欄位的純文字值映射至資料庫中存放的加密值。 *LastName* 

此信標會從 `LastName` 欄位中的純文字值計算 HMACs。每個 HMAC 輸出都會截斷，使其不再完全符合純文字值。例如， 的完整雜湊和截斷的雜湊`Jones`可能如下所示。

**完成雜湊**

`2aa4e9b404c68182562b6ec761fcca5306de527826a69468885e59dc36d0c3f824bdd44cab45526f70a2a18322000264f5451acf75f9f817e2b35099d408c833`

**截斷的雜湊**

`b35099d408c833`

設定標準信標之後，您可以在 `LastName` 欄位上執行相等性搜尋。例如，如果您想要搜尋 `Jones`，請使用 *LastName* 信標來執行下列查詢。

```
LastName = Jones
```

 AWS Database Encryption SDK 會自動篩選掉誤報，並傳回查詢的純文字結果。

# 信標
<a name="beacons"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

信標是截斷的雜湊型訊息驗證碼 (HMAC) 標籤，可在寫入欄位的純文字值與實際存放在資料庫中的加密值之間建立映射。信標不會變更 欄位的加密狀態。信標會透過欄位的純文字值計算 HMAC，並將其與加密值一起存放。此 HMAC 輸出是該欄位純文字值的一對一 (1：1) 比對。HMAC 輸出會截斷，讓多個不同的純文字值對應至相同的截斷 HMAC 標籤。這些誤報會限制未經授權的使用者識別純文字值辨別資訊的能力。

信標只能從[密碼編譯動作](concepts.md#crypt-actions)`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`中標記為 `ENCRYPT_AND_SIGN`、 `SIGN_ONLY`或 的欄位建構。信標本身不會簽署或加密。您無法以標記為 的欄位建構信標`DO_NOTHING`。

您設定的信標類型會決定您可以執行的查詢類型。支援可搜尋加密的信標有兩種類型。*標準信標*會執行相等性搜尋。*複合信標*結合文字純文字字串和標準信標，以執行複雜的資料庫操作。[設定信標](configure-beacons.md)之後，您必須為每個信標設定次要索引，才能搜尋加密的欄位。如需詳細資訊，請參閱[使用信標設定次要索引](ddb-searchable-encryption.md#ddb-beacon-indexes)。

**Topics**
+ [標準信標](#standard-beacon-overview)
+ [複合信標](#compound-beacon-overview)

## 標準信標
<a name="standard-beacon-overview"></a>

標準信標是在資料庫中實作可搜尋加密的最簡單方法。他們只能對單一加密或虛擬欄位執行等式搜尋。若要了解如何設定標準信標，請參閱[設定標準信標](configure-beacons.md#config-standard-beacons)。



標準信標建構來源的欄位稱為*信標來源*。它可識別信標需要映射的資料位置。信標來源可以是加密欄位或*虛擬欄位*。每個標準信標中的信標來源必須是唯一的。您無法設定具有相同信標來源的兩個信標。

標準信標可用於對加密或虛擬欄位執行等式搜尋。或者，它們可用來建構複合信標，以執行更複雜的資料庫操作。為了協助您組織和管理標準信標， AWS 資料庫加密 SDK 提供下列選用*信標樣式*，可定義標準信標的預期用途。如需詳細資訊，請參閱[定義信標樣式](configure-beacons.md#define-beacon-styles)。

您可以建立執行單一加密欄位相等性搜尋的標準信標，也可以建立建立虛擬欄位，在多個 `ENCRYPT_AND_SIGN`、 `SIGN_ONLY`和 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 欄位的串連上執行相等性搜尋的標準信標。



**虛擬欄位**  
虛擬欄位是從一或多個來源欄位建構的概念欄位。建立虛擬欄位不會將新欄位寫入您的記錄。虛擬欄位不會明確存放在您的資料庫中。它用於標準信標組態，提供信標指示，說明如何識別欄位的特定區段，或串連記錄中的多個欄位以執行特定查詢。虛擬欄位至少需要一個加密欄位。  
下列範例示範您可以使用虛擬欄位執行的轉換和查詢類型。在應用程式中，此範例中使用的範例欄位可能不符合信標的[分佈](searchable-encryption.md#searchable-encryption-distribution)和[相互關聯](searchable-encryption.md#searchable-encryption-correlated-values)唯一性建議。
例如，如果您想要對 `FirstName`和 `LastName` 欄位的串連執行等式搜尋，您可以建立下列其中一個虛擬欄位。  
+ 虛擬`NameTag`欄位，從`FirstName`欄位的第一個字母開始建構，後面接著 `LastName` 欄位，全部小寫。此虛擬欄位可讓您查詢 `NameTag=mjones`。
+ 虛擬`LastFirst`欄位，由 `LastName` 欄位建構，後面接著 `FirstName` 欄位。此虛擬欄位可讓您查詢 `LastFirst=JonesMary`。
或者，如果您想要對加密欄位的特定區段執行相等性搜尋，請建立虛擬欄位來識別您要查詢的區段。  
例如，如果您想要使用 IP 地址的前三個區段來查詢加密`IPAddress`欄位，請建立下列虛擬欄位。  
+ 由 建構的虛擬`IPSegment`欄位`Segments(‘.’, 0, 3)`。此虛擬欄位可讓您查詢 `IPSegment=192.0.2`。查詢會傳回`IPAddress`值開頭為 "192.0.2" 的所有記錄。
虛擬欄位必須是唯一的。兩個虛擬欄位無法從完全相同的來源欄位建構。  
如需設定虛擬欄位和使用它們的信標的說明，請參閱[建立虛擬欄位](configure-beacons.md#create-virtual-field)。

## 複合信標
<a name="compound-beacon-overview"></a>

複合信標會建立索引，以改善查詢效能，並可讓您執行更複雜的資料庫操作。您可以使用複合信標來結合文字純文字字串和標準信標，對加密的記錄執行複雜的查詢，例如從單一索引查詢兩種不同的記錄類型，或使用排序索引鍵查詢欄位組合。如需更多複合信標解決方案範例，請參閱[選擇信標類型](choosing-beacon-type.md)。

複合信標可以從標準信標或標準信標和已簽章欄位的組合建構。它們是從組件清單建構而成。所有複合信標都應包含[加密部分的](configure-beacons.md#encrypted-parts)清單，以識別信標中包含`ENCRYPT_AND_SIGN`的欄位。每個`ENCRYPT_AND_SIGN`欄位都必須由標準信標識別。更複雜的複合信標也可能包含識別信標中包含的純文字`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`欄位的[已簽章部分](configure-beacons.md#signed-parts)清單，以及識別複合信標組合欄位的所有可能方式的[建構函數部分](configure-beacons.md#constructor-parts)清單。

**注意**  
 AWS Database Encryption SDK 也支援*簽署的信標*，這些信標可以完全從純文字`SIGN_ONLY`和`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`欄位設定。已簽章的信標是一種複合信標，可對已簽章但未加密的欄位編製索引並執行複雜的查詢。如需詳細資訊，請參閱[建立簽章的信標](configure.md#signed-beacons)。

如需設定複合信標的說明，請參閱[設定複合信標](configure-beacons.md#config-compound-beacons)。

您設定複合信標的方式決定其可執行的查詢類型。例如，您可以選用一些加密和已簽章的組件，以便在查詢中提供更多彈性。如需複合信標可執行之查詢類型的詳細資訊，請參閱 [查詢信標](using-beacons.md#querying-beacons)。

# 規劃信標
<a name="plan-searchable-encryption"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

信標設計為在新的未填入資料庫中實作。在現有資料庫中設定的任何信標只會映射寫入資料庫的新記錄。信標是根據欄位的純文字值計算，一旦欄位加密，信標就無法映射現有資料。使用信標撰寫新記錄之後，您就無法更新信標的組態。不過，您可以為新增至記錄的新欄位新增新信標。

若要實作可搜尋加密，您必須使用[AWS KMS 階層式 keyring](use-hierarchical-keyring.md) 來產生、加密和解密用於保護記錄的資料金鑰。如需詳細資訊，請參閱[使用階層式 keyring 進行可搜尋的加密](use-hierarchical-keyring.md#searchable-encryption-hierarchical-keyrings)。

您必須先檢閱加密需求、資料庫存取模式和威脅模型，以判斷資料庫的最佳解決方案，才能設定可搜尋加密[的信標](searchable-encryption.md#beacon-definition)。

您設定的[信標類型](beacons.md)決定您可以執行的查詢類型。您在標準[信標組態中指定的信標長度](choosing-beacon-length.md)會決定指定信標產生的預期誤報數量。我們強烈建議識別和規劃您在設定信標之前需要執行的查詢類型。使用信標後，就無法更新組態。

強烈建議您在設定任何信標之前，先檢閱並完成下列任務。
+ [判斷信標是否適合您的資料集](searchable-encryption.md#are-beacons-right-for-me)
+ [選擇信標類型](choosing-beacon-type.md)
+ [選擇信標長度](choosing-beacon-length.md)
+ [選擇信標名稱](choosing-beacon-name.md)

當您為資料庫規劃可搜尋的加密解決方案時，請記住下列信標唯一性要求。
+ **每個標準信標都必須具有唯一的[信標來源](beacons.md#beacon-source)**

  多個標準信標無法從相同的加密或虛擬欄位建構。

  不過，單一標準信標可用來建構多個複合信標。
+ **避免使用與現有標準信標重疊的來源欄位建立虛擬欄位**

  從虛擬欄位建構標準信標，其中包含用來建立另一個標準信標的來源欄位，可以降低兩個信標的安全性。

  如需詳細資訊，請參閱[虛擬欄位的安全考量](configure-beacons.md#virtual-field-considerations)。

## 多租戶資料庫的考量事項
<a name="planning-multitenant-beacons"></a>

若要查詢在多租用戶資料庫中設定的信標，您必須包含 欄位，該欄位存放與在查詢中加密記錄的租用戶`branch-key-id`相關聯的 。您可以在定義[信標金鑰來源時定義](use-hierarchical-keyring.md#beacon-key-source)此欄位。若要讓查詢成功，此欄位中的值必須識別重新計算信標所需的適當信標金鑰資料。

設定信標之前，您必須決定計劃如何在查詢`branch-key-id`中包含 。如需在查詢`branch-key-id`中包含 之不同方式的詳細資訊，請參閱 [查詢多租戶資料庫中的信標](searchable-encryption-multitenant.md#query-multitenant-beacons)。

# 選擇信標類型
<a name="choosing-beacon-type"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

使用可搜尋的加密，您可以透過將加密欄位中的純文字值與*信標*映射來搜尋加密的記錄。您設定的信標類型決定您可以執行的查詢類型。

我們強烈建議識別和規劃您在設定信標之前需要執行的查詢類型。[設定信標](configure-beacons.md)之後，您必須先為每個信標設定次要索引，才能搜尋加密的欄位。如需詳細資訊，請參閱[使用信標設定次要索引](ddb-searchable-encryption.md#ddb-beacon-indexes)。

信標會在寫入欄位的純文字值與實際存放在資料庫中的加密值之間建立映射。您無法比較兩個標準信標的值，即使它們包含相同的基礎純文字。兩個標準信標將為相同的純文字值產生兩個不同的 HMAC 標籤。因此，標準信標無法執行下列查詢。
+ `beacon1 = beacon2`
+ `beacon1 IN (beacon2)`
+ `value IN (beacon1, beacon2, ...)`
+ `CONTAINS(beacon1, beacon2)`

只有在您比較複合信標的[簽章部分](configure-beacons.md#signed-parts)時，才能執行上述查詢，但 `CONTAINS`運算子除外，您可以搭配複合信標使用，以識別組合信標包含的加密或簽章欄位的完整值。當您比較已簽署組件時，您可以選擇包含[加密組件](configure-beacons.md#encrypted-parts)的字首，但不能包含欄位的加密值。如需標準和複合信標可執行之查詢類型的詳細資訊，請參閱[查詢信標](using-beacons.md#querying-beacons)。

在檢閱資料庫存取模式時，請考慮下列可搜尋的加密解決方案。下列範例定義要設定哪些信標以滿足不同的加密和查詢需求。

## 標準信標
<a name="plan-standard-beacon"></a>

[標準信標](beacons.md#standard-beacon-overview)只能執行等式搜尋。您可以使用標準信標來執行下列查詢。

### 查詢單一加密欄位
<a name="se-example1"></a>

如果您想要識別包含加密欄位特定值的記錄，請建立標準信標。

#### 範例
<a name="example1"></a>

針對下列範例，請考慮名為 的資料庫`UnitInspection`，以追蹤生產設施的檢查資料。資料庫中的每個記錄都包含稱為 `work_id`、`inspector_id_last4`、 `inspection_date`和 的欄位`unit`。完整檢測器 ID 是介於 0 到 99，999，999 之間的數字。不過，為了確保資料集均勻分佈， `inspector_id_last4`只會存放檢測器 ID 的最後四位數字。資料庫中的每個欄位都由主索引鍵 識別`work_id`。`inspector_id_last4` 和 `unit` 欄位會在[密碼編譯動作](concepts.md#crypt-actions)`ENCRYPT_AND_SIGN`中標記。

以下是`UnitInspection`資料庫中純文字項目的範例。

```
{
    "work_id": "1c7fcff3-6e74-41a8-b7f7-925dc039830b",
    "inspection_date": 2023-06-07,
    "inspector_id_last4": 8744,
    "unit": 229304973450   
}
```

**查詢記錄中的單一加密欄位**  
如果 `inspector_id_last4` 欄位需要加密，但您仍然需要查詢其是否完全相符，請從 `inspector_id_last4` 欄位建構標準信標。然後，使用標準信標來建立次要索引。您可以使用此次要索引來查詢加密`inspector_id_last4`欄位。

如需設定標準信標的說明，請參閱[設定標準信標](configure-beacons.md#config-standard-beacons)。

### 查詢虛擬欄位
<a name="se-example2"></a>

[虛擬欄位](beacons.md#virtual-field)是從一或多個來源欄位建構的概念欄位。如果您想要對加密欄位的特定區段執行相等性搜尋，或對多個欄位的串連執行相等性搜尋，請從虛擬欄位建構標準信標。所有虛擬欄位必須至少包含一個加密的來源欄位。

#### 範例
<a name="example2"></a>

下列範例會建立`Employees`資料庫的虛擬欄位。以下是`Employees`資料庫中的純文字記錄範例。

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

**查詢加密欄位的區段**  
在此範例中， `SSN` 欄位已加密。  
如果您想要使用社會安全號碼的最後四位數字查詢`SSN`欄位，請建立虛擬欄位來識別您計劃查詢的客群。  
由 建構的虛擬`Last4SSN`欄位`Suffix(4)`可讓您查詢 `Last4SSN=0000`。使用此虛擬欄位來建構標準信標。然後，使用標準信標來建立次要索引。您可以使用此次要索引來查詢虛擬欄位。此查詢會傳回`SSN`值以您指定的後四位數字結尾的所有記錄。

**查詢多個欄位的串連**  
下列範例示範您可以使用虛擬欄位執行的轉換和查詢類型。在應用程式中，此範例中使用的範例欄位可能不符合信標的[分佈](searchable-encryption.md#searchable-encryption-distribution)和[相互關聯](searchable-encryption.md#searchable-encryption-correlated-values)唯一性建議。
如果您想要對 `FirstName`和 `LastName` 欄位的串連執行相等性搜尋，您可以建立虛擬`NameTag`欄位，該欄位是從`FirstName`欄位的第一個字母開始建構，後面接著 `LastName` 欄位，全部為小寫。使用此虛擬欄位來建構標準信標。然後，使用標準信標來建立次要索引。您可以使用此次要索引來`NameTag=mjones`查詢虛擬欄位。  
至少必須加密其中一個來源欄位。`FirstName` 或 `LastName` 可以加密，或兩者都可以加密。任何純文字來源欄位都必須在您的[密碼編譯動作](concepts.md#crypt-actions)`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`中標示為 `SIGN_ONLY`或 。

如需設定虛擬欄位和使用它們的信標的說明，請參閱[建立虛擬欄位](configure-beacons.md#create-virtual-field)。

## 複合信標
<a name="plan-compound-beacons"></a>

[複合信標](beacons.md#compound-beacon-overview)會從文字純文字字串和標準信標建立索引，以執行複雜的資料庫操作。您可以使用複合信標來執行下列查詢。

### 查詢單一索引上加密欄位的組合
<a name="se-example3"></a>

如果您需要查詢單一索引上加密欄位的組合，請建立複合信標，該信標會結合為每個加密欄位建構的個別標準信標，以形成單一索引。

設定複合信標之後，您可以建立次要索引，指定複合信標做為分割區索引鍵來執行完全相符的查詢，或使用排序索引鍵來執行更複雜的查詢。將複合信標指定為排序索引鍵的次要索引可以執行完全相符的查詢和更自訂的複雜查詢。

#### 範例
<a name="example3"></a>

針對下列範例，請考慮名為 的資料庫`UnitInspection`，以追蹤生產設施的檢查資料。資料庫中的每個記錄都包含稱為 `work_id`、`inspector_id_last4`、 `inspection_date`和 的欄位`unit`。完整檢測器 ID 是介於 0 到 99，999，999 之間的數字。不過，為了確保資料集均勻分佈， `inspector_id_last4`只會存放檢測器 ID 的最後四位數字。資料庫中的每個欄位都由主索引鍵 識別`work_id`。[密碼編譯動作](concepts.md#crypt-actions)`ENCRYPT_AND_SIGN`中會標記 `inspector_id_last4`和 `unit` 欄位。

以下是`UnitInspection`資料庫中純文字項目的範例。

```
{
    "work_id": "1c7fcff3-6e74-41a8-b7f7-925dc039830b",
    "inspection_date": 2023-06-07,
    "inspector_id_last4": 8744,
    "unit": 229304973450
}
```

**對加密欄位的組合執行相等性搜尋**  
如果您想要在 上查詢`UnitInspection`資料庫的完全相符項目`inspector_id_last4.unit`，請先為 `inspector_id_last4`和 `unit` 欄位建立不同的標準信標。然後，從兩個標準信標建立複合信標。  
設定複合信標之後，請建立次要索引，將複合信標指定為分割區索引鍵。使用此次要索引查詢 上的完全相符項目`inspector_id_last4.unit`。例如，您可以查詢此信標，以尋找檢查器為指定單位執行的檢查清單。

**對加密欄位的組合執行複雜的查詢**  
如果您想要查詢 `inspector_id_last4`和 上的`UnitInspection`資料庫`inspector_id_last4.unit`，請先為 `inspector_id_last4`和 `unit` 欄位建立不同的標準信標。然後，從兩個標準信標建立複合信標。  
設定複合信標之後，請建立次要索引，指定複合信標做為排序索引鍵。使用此次要索引查詢`UnitInspection`資料庫是否有以特定檢測器開頭的項目，或查詢資料庫以取得特定檢測器檢查之特定單位 ID 範圍內所有單位的清單。您也可以在 上執行完全相符的搜尋`inspector_id_last4.unit`。

如需設定複合信標的說明，請參閱[設定複合信標](configure-beacons.md#config-compound-beacons)。

### 查詢單一索引上加密和純文字欄位的組合
<a name="se-example4"></a>

如果您需要查詢單一索引上加密和純文字欄位的組合，請建立複合信標，結合個別標準信標和純文字欄位以形成單一索引。用於建構複合信標的純文字欄位必須在[密碼編譯動作](concepts.md#crypt-actions)`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`中標記 `SIGN_ONLY`或 。

設定複合信標之後，您可以建立次要索引，指定複合信標做為分割區索引鍵來執行完全相符的查詢，或使用排序索引鍵來執行更複雜的查詢。將複合信標指定為排序索引鍵的次要索引可以執行完全相符的查詢和更自訂的複雜查詢。

#### 範例
<a name="example4"></a>

針對下列範例，請考慮名為 的資料庫`UnitInspection`，以追蹤生產設施的檢查資料。資料庫中的每個記錄都包含稱為 `work_id`、`inspector_id_last4`、 `inspection_date`和 的欄位`unit`。完整檢測器 ID 是介於 0 到 99，999，999 之間的數字。不過，為了確保資料集均勻分佈， `inspector_id_last4`只會存放檢測器 ID 的最後四位數字。資料庫中的每個欄位都由主索引鍵 識別`work_id`。[密碼編譯動作](concepts.md#crypt-actions)`ENCRYPT_AND_SIGN`中會標記 `inspector_id_last4`和 `unit` 欄位。

以下是`UnitInspection`資料庫中純文字項目的範例。

```
{
    "work_id": "1c7fcff3-6e74-41a8-b7f7-925dc039830b",
    "inspection_date": 2023-06-07,
    "inspector_id_last4": 8744,
    "unit": 229304973450
}
```

**在欄位組合上執行相等性搜尋**  
如果您想要查詢`UnitInspection`資料庫是否有特定檢查人員在特定日期執行的檢查，請先為 `inspector_id_last4` 欄位建立標準信標。`inspector_id_last4` 欄位會在[密碼編譯動作](concepts.md#crypt-actions)`ENCRYPT_AND_SIGN`中標記。所有加密的組件都需要自己的標準信標。`inspection_date` 欄位已標記`SIGN_ONLY`，不需要標準信標。接著，從 `inspection_date` 欄位和`inspector_id_last4`標準信標建立複合信標。  
設定複合信標之後，請建立次要索引，將複合信標指定為分割區索引鍵。使用此次要索引來查詢資料庫是否有與特定檢查器和檢查日期完全相符的記錄。例如，您可以查詢資料庫，以取得 ID 結尾為 的檢查器在特定日期`8744`執行的所有檢查清單。

**在欄位組合上執行複雜的查詢**  
如果您想要查詢資料庫是否有在 `inspection_date`範圍內執行的檢查，或查詢資料庫是否有對 `inspector_id_last4`或 `inspection_date`限制的特定執行的檢查`inspector_id_last4.unit`，請先為 `inspector_id_last4`和 `unit` 欄位建立不同的標準信標。然後，從純文字`inspection_date`欄位和兩個標準信標建立複合信標。  
設定複合信標之後，請建立次要索引，指定複合信標做為排序索引鍵。使用此次要索引，對特定檢查器在特定日期執行的檢查執行查詢。例如，您可以查詢資料庫，以取得在相同日期檢查的所有單位清單。或者，您可以在指定的檢查日期範圍內，查詢資料庫以取得在特定單位上執行的所有檢查清單。

如需設定複合信標的說明，請參閱[設定複合信標](configure-beacons.md#config-compound-beacons)。

# 選擇信標長度
<a name="choosing-beacon-length"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

當您將新值寫入設定為可搜尋加密的加密欄位時， AWS 資料庫加密 SDK 會透過純文字值計算 HMAC。此 HMAC 輸出是該欄位純文字值的一對一 (1：1) 比對。HMAC 輸出會截斷，讓多個不同的純文字值對應至相同的截斷 HMAC 標籤。這些碰撞或*誤報*會限制未經授權的使用者識別純文字值辨別資訊的能力。

為每個信標產生的偽陽性平均數量取決於截斷後剩餘的信標長度。您只需要在設定標準信標時定義信標長度。複合信標使用其建構之標準信標的信標長度。

信標不會變更 欄位的加密狀態。不過，當您使用信標時，查詢的效率與資料分佈的公開資訊量之間存在固有權衡。

可搜尋加密的目標是使用信標對加密資料執行查詢，以降低與用戶端加密資料庫相關的效能成本。信標會與其計算來源的加密欄位一起存放。這表示他們可以顯示有關資料集分佈的辨別資訊。在極端情況下，未經授權的使用者可能可以分析發佈的相關資訊，並使用它來識別欄位的純文字值。選擇正確的信標長度有助於降低這些風險，並維護分發的機密性。

檢閱您的威脅模型，以判斷您需要的安全層級。例如，擁有資料庫存取權但不應該存取純文字資料的人員越多，您可能想要保護資料集分佈的機密性就越多。為了提高機密性，信標需要產生更多誤報。提高機密性會導致查詢效能降低。

**安全性與效能**
+ **過長**的信標長度會產生太少的誤報，並可能顯示有關資料集分佈的辨別資訊。
+ **過短**的信標長度會產生太多誤報，並提高查詢的效能成本，因為它需要更廣泛的資料庫掃描。

判斷解決方案的適當信標長度時，您必須找到可充分保留資料安全性的長度，而不會影響查詢效能的絕對必要性。信標保留的安全數量取決於資料集的[分佈](searchable-encryption.md#searchable-encryption-distribution)，以及信標建構來源欄位的[相互關聯](searchable-encryption.md#searchable-encryption-correlated-values)性。下列主題假設您的信標是統一分佈的，且不包含相互關聯的資料。

**Topics**
+ [計算信標長度](#calculate-beacon-length)
+ [範例](#beacon-length-example)

## 計算信標長度
<a name="calculate-beacon-length"></a>

信標長度以*位元*定義，是指截斷後保留的 HMAC 標籤位元數。建議的信標長度取決於資料集分佈、相關值的存在，以及您的特定安全性和效能需求。如果您的資料集是統一分佈的，您可以使用下列方程式和程序來協助識別實作的最佳信標長度。這些方程式只會估計信標會產生的平均誤報次數，並不保證資料集中的每個唯一值都會產生特定數量的誤報。

**注意**  
這些方程式的有效性取決於資料集的分佈。如果您的資料集未統一分佈，請參閱 [信標是否適合我的資料集？](searchable-encryption.md#are-beacons-right-for-me)。  
一般而言，資料集越來自統一分佈，縮短信標長度所需的時間就越多。

1. 

   **估算人口**

   人口是標準信標建構來源欄位中的預期唯一值數量，不是存放在欄位中的預期值總數。例如，請考慮可識別員工會議位置的加密`Room`欄位。`Room` 欄位預計會儲存 100，000 個總值，但只有 50 個不同的會議室可供員工預留用於會議。這表示人口為 50，因為只有 50 個可能的唯一值可以存放在 `Room` 欄位中。
**注意**  
如果您的標準信標是從[虛擬欄位](beacons.md#virtual-field)建構的，則用於計算信標長度的人口是虛擬欄位建立的唯一組合數量。

   估算人口時，請務必考慮資料集的預計增長。使用信標撰寫新記錄之後，您就無法更新信標長度。檢閱您的威脅模型和任何現有的資料庫解決方案，以建立您預期此欄位在未來五年內存放的唯一值數量的預估值。

   您的人口不需要精確。首先，識別目前資料庫中的唯一值數目，或預估您預期在第一年存放的唯一值數目。接著，使用下列問題來協助您判斷未來五年內唯一值的預計增長。
   + 您是否預期唯一值會乘以 10？ 
   + 您是否預期唯一值會乘以 100？ 
   + 您是否預期唯一值會乘以 1000？ 

   50，000 和 60，000 個唯一值之間的差異並不顯著，它們都會產生相同的建議信標長度。不過，50，000 和 500，000 唯一值之間的差異將大幅影響建議的信標長度。

   請考慮檢閱常見資料類型頻率的公有資料，例如郵遞區號或姓氏。例如，美國有 41，707 個郵遞區號。您使用的人口應與您自己的資料庫成比例。如果資料庫中`ZIPCode`的欄位包含來自整個美國的資料，則可以將人口定義為 41，707，即使該`ZIPCode`欄位*目前*沒有 41，707 個唯一值。如果資料庫中`ZIPCode`的欄位只包含來自單一狀態的資料，而且只包含來自單一狀態的資料，則您可以將人口定義為該狀態的郵遞區號總數，而不是 41，704。

1. **計算預期碰撞次數的建議範圍**

   若要判斷指定欄位的適當信標長度，您必須先識別預期碰撞數量的適當範圍。預期的碰撞數量代表映射到特定 HMAC 標籤的唯一純文字值的平均預期數量。一個唯一純文字值的預期誤報數量小於預期的碰撞數量。

   我們建議預期的碰撞數量大於或等於兩個，且小於人口的平方根。下列方程式只有在您的人口有 16 個或更多唯一值時才有效。

   ```
   2 ≤ number of collisions < √(Population)
   ```

   如果碰撞次數少於兩個，則信標會產生太少的誤報。我們建議使用兩個 作為預期碰撞的最小數量，因為它表示平均而言，欄位中的每個唯一值都會映射到另一個唯一值來產生至少一個偽陽性。

1. **計算信標長度的建議範圍**

   識別預期碰撞的最小和最大數量之後，請使用下列方程式來識別適當的信標長度範圍。

   ```
   number of collisions = Population * 2-(beacon length)
   ```

   首先，解決預期碰撞數量等於兩個 （預期碰撞的最低建議數量） 的**信標長度**。

   ```
   2 = Population * 2-(beacon length)
   ```

   然後，解決預期碰撞數量等於人口平方根的**信標長度** （建議的最大預期碰撞數量）。

   ```
   √(Population) = Population * 2-(beacon length)
   ```

   我們建議將此方程式產生的輸出四捨五入至較短的信標長度。例如，如果方程式產生 15.6 的信標長度，我們建議將該值四捨五入到 15 位元，而不是四捨五入到 16 位元。

1. **選擇信標長度**

   這些方程式只會識別您欄位的建議信標長度範圍。我們建議您盡可能使用較短的信標長度來維護資料集的安全性。不過，您實際使用的信標長度取決於您的威脅模型。在檢閱威脅模型以判斷欄位的最佳信標長度時，請考慮您的效能需求。

   使用較短的信標長度會降低查詢效能，而使用較長的信標長度則會降低安全性。一般而言，如果您的資料集[分佈](searchable-encryption.md#searchable-encryption-distribution)不均勻，或者如果您從[關聯](searchable-encryption.md#searchable-encryption-correlated-values)欄位建構不同的信標，則需要使用較短的信標長度，將資料集分佈的相關資訊量降至最低。

   如果您檢閱威脅模型，並決定任何顯示有關欄位分佈的辨別資訊不會對您的整體安全性造成威脅，您可以選擇使用比您計算的建議範圍更長的信標長度。例如，如果您將欄位的信標長度建議範圍計算為 9-16 位元，您可以選擇使用 24 位元的信標長度，以避免任何效能損失。

   請謹慎選擇您的信標長度。使用信標撰寫新記錄之後，您就無法更新信標長度。

## 範例
<a name="beacon-length-example"></a>

考慮在[密碼編譯動作](concepts.md#crypt-actions)`ENCRYPT_AND_SIGN`中將 `unit` 欄位標記為 的資料庫。若要設定 `unit` 欄位的標準信標，我們需要判斷該`unit`欄位的預期誤報數和信標長度。

1. 估計人口

   檢閱我們的威脅模型和目前的資料庫解決方案後，我們預期 `unit` 欄位最終會有 100，000 個唯一值。

   這表示**人口 = 100，000**。

1. 計算預期碰撞次數的建議範圍。

   在此範例中，預期的碰撞數量應介於 2 到 316 之間。

   ```
   2 ≤ number of collisions < √(Population)
   ```

   1. 

      ```
      2 ≤ number of collisions < √(100,000)
      ```

   1. 

      ```
      2 ≤ number of collisions < 316
      ```

1. 計算信標長度的建議範圍。

   在此範例中，信標長度應介於 9-16 位元之間。

   ```
   number of collisions = Population * 2-(beacon length)
   ```

   1. 計算信標長度，其中預期的碰撞數量等於**步驟 2 **中識別的最小值。

      ```
      2 = 100,000 * 2-(beacon length)
      ```

      信標長度 = 15.6 或 15 位元

   1. 計算信標長度，其中預期的碰撞數量等於**步驟 2 **中識別的最大值。

      ```
      316 = 100,000 * 2-(beacon length)
      ```

      信標長度 = 8.3 或 8 位元

1. 判斷適合您安全和效能需求的信標長度。

   對於低於 15 的每個位元，效能成本和安全性會加倍。
   + 16 位元
     + 平均而言，每個唯一值都會對應至其他 1.5 個單位。
     + 安全性：具有相同截斷 HMAC 標籤的兩個記錄有 66% 可能有相同的純文字值。
     + 效能：查詢會為您實際請求的每 10 筆記錄擷取 15 筆記錄。
   + 14 位元
     + 平均而言，每個唯一值都會對應至 6.1 個其他單位。
     + 安全性：具有相同截斷 HMAC 標籤的兩個記錄有 33% 可能有相同的純文字值。
     + 效能：查詢會為您實際請求的每 10 筆記錄擷取 30 筆記錄。

# 選擇信標名稱
<a name="choosing-beacon-name"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

每個信標都由唯一的*信標名稱*識別。設定信標後，信標名稱即為您在查詢加密欄位時所使用的名稱。信標名稱可與加密欄位或[虛擬欄位](beacons.md#virtual-field)的名稱相同，但不能與未加密欄位的名稱相同。兩個不同的信標不能有相同的信標名稱。

如需示範如何命名和設定信標的範例，請參閱[設定信標](configure-beacons.md)。



**命名標準信標**  
命名標準信標時，強烈建議您的信標名稱盡可能解析為[*信標來源*](beacons.md#beacon-source)。這表示您標準信標建構來源的加密或[虛擬](beacons.md#virtual-field)欄位的信標名稱和名稱相同。例如，如果您要為名為 的加密欄位建立標準信標`LastName`，您的信標名稱也應該是 `LastName`。

當您的信標名稱與信標來源相同時，您可以從組態省略信標來源， AWS 資料庫加密 SDK 會自動使用信標名稱做為信標來源。

# 設定信標
<a name="configure-beacons"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

支援可搜尋加密的信標有兩種類型。標準信標會執行相等性搜尋。它們是在資料庫中實作可搜尋加密的最簡單方法。複合信標結合文字純文字字串和標準信標，以執行更複雜的查詢。

信標設計為在新的未填入資料庫中實作。在現有資料庫中設定的任何信標只會映射寫入資料庫的新記錄。信標是根據欄位的純文字值計算，一旦欄位加密，信標就無法映射現有資料。使用信標撰寫新記錄之後，您就無法更新信標的組態。不過，您可以為新增至記錄的新欄位新增新信標。

決定您的存取模式之後，設定信標應該是資料庫實作的第二個步驟。然後，設定所有信標之後，您需要建立[AWS KMS 階層式 keyring](use-hierarchical-keyring.md)、定義信標版本、[為每個信標設定次要索引](ddb-searchable-encryption.md#ddb-beacon-indexes)、定義[密碼編譯動作](concepts.md#crypt-actions)，以及設定資料庫和 AWS 資料庫加密 SDK 用戶端。如需詳細資訊，請參閱[使用信標](using-beacons.md)。

為了更輕鬆地定義信標版本，建議您為標準信標和複合信標建立清單。在您設定每個信標時，將您建立的每個信標新增至個別的標準或複合信標清單。

**Topics**
+ [設定標準信標](#config-standard-beacons)
+ [設定複合信標](#config-compound-beacons)
+ [範例組態](beacon-config-examples.md)

## 設定標準信標
<a name="config-standard-beacons"></a>

[標準信標](beacons.md#standard-beacon-overview)是在資料庫中實作可搜尋加密的最簡單方法。他們只能對單一加密或虛擬欄位執行等式搜尋。

### 組態語法範例
<a name="standard-config-syntax"></a>

------
#### [ Java ]

```
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon exampleStandardBeacon = StandardBeacon.builder()
    .name("beaconName")
    .length(beaconLengthInBits)
    .build();
standardBeaconList.add(exampleStandardBeacon);
```

------
#### [ C\$1 / .NET ]

```
var standardBeaconList = new List<StandardBeacon>();
StandardBeacon exampleStandardBeacon = new StandardBeacon
  {
    Name = "beaconName",
    Length = 10
  };
standardBeaconList.Add(exampleStandardBeacon);
```

------
#### [ Rust ]

```
let standard_beacon_list = vec![
    StandardBeacon::builder().name("beacon_name").length(beacon_length_in_bits).build()?,
```

------

若要設定標準信標，請提供下列值。

**信標名稱**  
您在查詢加密欄位時使用的名稱。  
信標名稱可與加密欄位或虛擬欄位的名稱相同，但不能與未加密欄位的名稱相同。我們強烈建議盡可能使用標準信標建構來源的加密欄位或[虛擬欄位](beacons.md#virtual-field)的名稱。兩個不同的信標不能有相同的信標名稱。如需判斷實作最佳信標名稱的說明，請參閱[選擇信標名稱](choosing-beacon-name.md)。

**信標長度**  
截斷後保留的信標雜湊值位元數。  
信標長度決定指定信標產生的平均誤報數。如需詳細資訊並協助判斷適合您實作的信標長度，請參閱[判斷信標長度](choosing-beacon-length.md)。

**信標來源 （選用）**  
標準信標的建構來源欄位。  
信標來源必須是參照巢狀欄位值的欄位名稱或索引。當您的信標名稱與信標來源相同時，您可以從組態省略信標來源， AWS 資料庫加密 SDK 會自動使用信標名稱做為信標來源。

### 建立虛擬欄位
<a name="create-virtual-field"></a>

若要建立[虛擬欄位](beacons.md#virtual-field)，您必須提供虛擬欄位的名稱和來源欄位的清單。您新增來源欄位至虛擬組件清單的順序會決定它們串連以建置虛擬欄位的順序。下列範例會串連兩個來源欄位，以建立虛擬欄位。

**注意**  
我們建議您先驗證虛擬欄位是否產生預期結果，再填入資料庫。如需詳細資訊，請參閱[測試信標輸出](ddb-searchable-encryption.md#ddb-beacon-testing)。

------
#### [ Java ]

**請參閱完整的程式碼範例**：[VirtualBeaconSearchableEncryptionExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java) 

```
List<VirtualPart> virtualPartList = new ArrayList<>();
    virtualPartList.add(sourceField1);
    virtualPartList.add(sourceField2);

VirtualField virtualFieldName = VirtualField.builder()
    .name("virtualFieldName")
    .parts(virtualPartList)
    .build();

List<VirtualField> virtualFieldList = new ArrayList<>();
    virtualFieldList.add(virtualFieldName);
```

------
#### [ C\$1 / .NET ]

**請參閱完整的程式碼範例**：[VirtualBeaconSearchableEncryptionExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/VirtualBeaconSearchableEncryptionExample.cs)

```
var virtualPartList = new List<VirtualPart> { sourceField1, sourceField2 };

var virtualFieldName = new VirtualField
{
    Name = "virtualFieldName",
    Parts = virtualPartList
};

var virtualFieldList = new List<VirtualField> { virtualFieldName };
```

------
#### [ Rust ]

**請參閱完整的程式碼範例**： [virtual\$1beacon\$1searchable\$1encryption.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/virtual_beacon_searchable_encryption.rs)

```
let virtual_part_list = vec![source_field_one, source_field_two];

let state_and_has_test_result_field = VirtualField::builder()
    .name("virtual_field_name")
    .parts(virtual_part_list)
    .build()?;

let virtual_field_list = vec![virtual_field_name];
```

------

若要使用來源欄位的特定區段建立虛擬欄位，您必須先定義轉換，才能將來源欄位新增至虛擬組件清單。

#### 虛擬欄位的安全考量
<a name="virtual-field-considerations"></a>

信標不會變更 欄位的加密狀態。不過，當您使用信標時，查詢的效率與資料分佈的公開資訊量之間存在固有權衡。您設定信標的方式會決定該信標所保留的安全層級。

避免使用與現有標準信標重疊的來源欄位建立虛擬欄位。建立包含已用於建立標準信標之來源欄位的虛擬欄位，可以降低兩個信標的安全層級。安全性降低的程度取決於其他來源欄位新增的熵層級。熵程度取決於額外來源欄位中唯一值的分佈，以及額外來源欄位對虛擬欄位整體大小貢獻的位元數。

您可以使用人口和[信標長度](choosing-beacon-length.md)來判斷虛擬欄位的來源欄位是否保留資料集的安全性。人口是欄位中唯一值的預期數量。您的人口不需要精確。如需估算欄位人口的說明，請參閱[估算人口](choosing-beacon-length.md#estimate-population)。

在檢閱虛擬欄位的安全性時，請考慮下列範例。
+ Beacon1 由 建構`FieldA`。 `FieldA` 的人口大於 **2 (Beacon1 長度）**。
+ Beacon2 由 建構`VirtualField`，其由 `FieldA`、`FieldC`、 `FieldB`和 建構`FieldD`。、`FieldC`、 `FieldB`和 共同`FieldD`擁有大於 **2N** 的人口

如果下列陳述式為 true，Beacon2 會同時保留 Beacon1 和 Beacon2 的安全性：

```
N ≥ (Beacon1 length)/2
```

及

```
N ≥ (Beacon2 length)/2
```

### 定義信標樣式
<a name="define-beacon-styles"></a>

標準信標可用於對加密或虛擬欄位執行等式搜尋。或者，它們可用來建構複合信標，以執行更複雜的資料庫操作。為了協助您組織和管理標準信標， AWS 資料庫加密 SDK 提供下列選用*信標樣式*，可定義標準信標的預期用途。

**注意**  
若要定義信標樣式，您必須使用 3.2 版或更新版本的 AWS 資料庫加密 SDK。將信標樣式新增至信標組態之前，先將新版本部署至所有讀取器。

------
#### [ PartOnly ]

定義為 的標準信標`PartOnly`只能用來定義複合信標的[加密部分](#encrypted-parts)。您無法直接查詢`PartOnly`標準信標。

**Java**  

```
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon exampleStandardBeacon = StandardBeacon.builder()
    .name("beaconName")
    .length(beaconLengthInBits)
    .style(
        BeaconStyle.builder()
           .partOnly(PartOnly.builder().build())
        .build()
    )
    .build();
standardBeaconList.add(exampleStandardBeacon);
```

**C\$1 / .NET**  

```
new StandardBeacon
{
    Name = "beaconName",
    Length = beaconLengthInBits,
    Style = new BeaconStyle
    {
        PartOnly = new PartOnly()
    }
}
```

**Rust**  

```
StandardBeacon::builder()
    .name("beacon_name")
    .length(beacon_length_in_bits)
    .style(BeaconStyle::PartOnly(PartOnly::builder().build()?))
    .build()?
```

------
#### [ Shared ]

根據預設，每個標準信標都會產生唯一的 HMAC 金鑰來計算信標。因此，您無法從兩個不同的標準信標對加密的欄位執行等式搜尋。定義為 的標準信標`Shared`會使用另一個標準信標的 HMAC 金鑰進行計算。

例如，如果您需要將`beacon1`欄位與`beacon2`欄位進行比較，請將 `beacon2`定義為使用來自 的 HMAC 金鑰`beacon1`進行計算的`Shared`信標。

**注意**  
在設定任何`Shared`信標之前，請考慮您的安全和效能需求。 `Shared`信標可能會增加有關資料集分佈的統計資訊量。例如，它們可能會顯示哪些共用欄位包含相同的純文字值。

**Java**  

```
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon exampleStandardBeacon = StandardBeacon.builder()
    .name("beacon2")
    .length(beaconLengthInBits)
    .style(
        BeaconStyle.builder()
           .shared(Shared.builder().other("beacon1").build())
        .build()
    )
    .build();
standardBeaconList.add(exampleStandardBeacon);
```

**C\$1 / .NET**  

```
new StandardBeacon
{
    Name = "beacon2",
    Length = beaconLengthInBits,
    Style = new BeaconStyle
    {
        Shared = new Shared { Other = "beacon1" }
    }
}
```

**Rust**  

```
StandardBeacon::builder()
    .name("beacon2")
    .length(beacon_length_in_bits)
    .style(BeaconStyle::Shared(
       Shared::builder().other("beacon1").build()?,
    ))
    .build()?
```

------
#### [ AsSet ]

根據預設，如果欄位值是集合， AWS 資料庫加密 SDK 會計算集合的單一標準信標。因此，您無法執行 `CONTAINS(a, :value)` `a`為加密欄位的查詢。定義為 的標準信標會`AsSet`計算集合中每個個別元素的個別標準信標值，並將信標值以集合形式存放在項目中。這可讓 AWS 資料庫加密 SDK 執行查詢 `CONTAINS(a, :value)`。

若要定義`AsSet`標準信標，集合中的元素必須來自相同的人口，以便它們都可以使用相同的[信標長度](choosing-beacon-length.md)。如果在計算信標值時發生衝突，信標集的元素可能少於純文字集。

**注意**  
在設定任何`AsSet`信標之前，請考慮您的安全和效能需求。 `AsSet`信標可能會增加有關資料集分佈的統計資訊量。例如，它們可能會顯示純文字集的大小。

**Java**  

```
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon exampleStandardBeacon = StandardBeacon.builder()
    .name("beaconName")
    .length(beaconLengthInBits)
    .style(
        BeaconStyle.builder()
           .asSet(AsSet.builder().build())
        .build()
    )
    .build();
standardBeaconList.add(exampleStandardBeacon);
```

**C\$1 / .NET**  

```
new StandardBeacon
{
    Name = "beaconName",
    Length = beaconLengthInBits,
    Style = new BeaconStyle
    {
        AsSet = new AsSet()
    }
}
```

**Rust**  

```
StandardBeacon::builder()
    .name("beacon_name")
    .length(beacon_length_in_bits)
    .style(BeaconStyle::AsSet(AsSet::builder().build()?))
    .build()?
```

------
#### [ SharedSet ]

定義為 的標準信標`SharedSet`結合了 `Shared`和 `AsSet`函數，讓您可以對集合和欄位的加密值執行相等性搜尋。這可讓 AWS 資料庫加密 SDK 執行查詢，`CONTAINS(a, b)`其中 `a` 是加密集，而 `b`是加密欄位。

**注意**  
在設定任何`Shared`信標之前，請考慮您的安全和效能需求。 `SharedSet`信標可能會增加有關資料集分佈的統計資訊量。例如，它們可能會顯示純文字集的大小，或哪些共用欄位包含相同的純文字值。

**Java**  

```
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon exampleStandardBeacon = StandardBeacon.builder()
    .name("beacon2")
    .length(beaconLengthInBits)
    .style(
        BeaconStyle.builder()
           .sharedSet(SharedSet.builder().other("beacon1").build())
        .build()
    )
    .build();
standardBeaconList.add(exampleStandardBeacon);
```

**C\$1 / .NET**  

```
new StandardBeacon
{
    Name = "beacon2",
    Length = beaconLengthInBits,
    Style = new BeaconStyle
    {
        SharedSet = new SharedSet { Other = "beacon1" }
    }
}
```

**Rust**  

```
StandardBeacon::builder()
    .name("beacon2")
    .length(beacon_length_in_bits)
    .style(BeaconStyle::SharedSet(
        SharedSet::builder().other("beacon1").build()?,
    ))
    .build()?
```

------

## 設定複合信標
<a name="config-compound-beacons"></a>

複合信標結合文字純文字字串和標準信標來執行複雜的資料庫操作，例如從單一索引查詢兩種不同的記錄類型，或查詢具有排序索引鍵的欄位組合。複合信標可以從 `ENCRYPT_AND_SIGN`、 `SIGN_ONLY`和 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 欄位建構。您必須為複合信標中包含的每個加密欄位建立標準信標。

**注意**  
我們建議您先驗證複合信標是否產生預期結果，再填入資料庫。如需詳細資訊，請參閱[測試信標輸出](ddb-searchable-encryption.md#ddb-beacon-testing)。

### 組態語法範例
<a name="compound-config-syntax"></a>

------
#### [ Java ]

**複合信標組態**

下列範例會在複合信標組態內於本機定義加密和簽章的組件清單。

```
List<CompoundBeacon> compoundBeaconList = new ArrayList<>();
CompoundBeacon exampleCompoundBeacon = CompoundBeacon.builder()
    .name("compoundBeaconName")
    .split(".")
    .encrypted(encryptedPartList) 
    .signed(signedPartList)                       
    .constructors(constructorList) 
    .build();
compoundBeaconList.add(exampleCompoundBeacon);
```

**信標版本定義**

下列範例會在信標版本中全域定義加密和已簽章的組件清單。如需定義信標版本的詳細資訊，請參閱[使用信標](using-beacons.md)。

```
 List<BeaconVersion> beaconVersions = new ArrayList<>();
beaconVersions.add(
    BeaconVersion.builder()
        .standardBeacons(standardBeaconList)
        .compoundBeacons(compoundBeaconList)
        .encryptedParts(encryptedPartList)
        .signedParts(signedPartList)
        .version(1) // MUST be 1
        .keyStore(keyStore)
        .keySource(BeaconKeySource.builder()
            .single(SingleKeyStore.builder()
                .keyId(branchKeyId)
                .cacheTTL(6000)
                .build())
            .build())
        .build()
);
```

------
#### [ C\$1 / .NET ]

**請參閱完整的程式碼範例**：[BeaconConfig.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/complexexample/BeaconConfig.cs)

**複合信標組態**

下列範例會在複合信標組態內於本機定義加密和簽章的組件清單。

```
var compoundBeaconList = new List<CompoundBeacon>();       
var exampleCompoundBeacon = new CompoundBeacon
 {
    Name = "compoundBeaconName",
    Split = ".",
    Encrypted = encryptedPartList,
    Signed = signedPartList,                        
    Constructors = constructorList 
 };
compoundBeaconList.Add(exampleCompoundBeacon);
```

**信標版本定義**

下列範例會在信標版本中全域定義加密和已簽章的組件清單。如需定義信標版本的詳細資訊，請參閱[使用信標](using-beacons.md)。

```
var beaconVersions = new List<BeaconVersion>
{
    new BeaconVersion
    {
        StandardBeacons = standardBeaconList,
        CompoundBeacons = compoundBeaconList,
        EncryptedParts = encryptedPartsList,
        SignedParts = signedPartsList,
        Version = 1, // MUST be 1
        KeyStore = keyStore,
        KeySource = new BeaconKeySource
        {
            Single = new SingleKeyStore
            {
                KeyId = branchKeyId,
                CacheTTL = 6000
            }
        }
    }
};
```

------
#### [ Rust ]

**請參閱完整的程式碼範例**： [beacon\$1config.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/complexexample/beacon_config.rs)

**複合信標組態**

下列範例會在複合信標組態內於本機定義加密和簽章的組件清單。

```
let compound_beacon_list = vec![
    CompoundBeacon::builder()
        .name("compound_beacon_name")
        .split(".")
        .encrypted(encrypted_parts_list)
        .signed(signed_parts_list)
        .constructors(constructor_list)
        .build()?
```

**信標版本定義**

下列範例會在信標版本中全域定義加密和已簽章的組件清單。如需定義信標版本的詳細資訊，請參閱[使用信標](using-beacons.md)。

```
let beacon_versions = BeaconVersion::builder()
    .standard_beacons(standard_beacon_list)
    .compound_beacons(compound_beacon_list)
    .encrypted_parts(encrypted_parts_list)
    .signed_parts(signed_parts_list)
    .version(1) // MUST be 1
    .key_store(key_store.clone())
    .key_source(BeaconKeySource::Single(
        SingleKeyStore::builder()
            .key_id(branch_key_id)
            .cache_ttl(6000)
            .build()?,
    ))
    .build()?;
let beacon_versions = vec![beacon_versions];
```

------

您可以在本機或全域定義的清單中定義[加密的組件](#encrypted-parts)和[已簽章的組件](#signed-parts)。我們建議您盡可能在[信標版本](using-beacons.md#beacon-version)中的全域清單中定義加密和簽章的組件。透過全域定義加密和簽章的組件，您可以定義每個組件一次，然後在多個複合信標組態中重複使用這些組件。如果您只打算使用加密或簽署的部分一次，您可以在複合信標組態的本機清單中定義它。您可以在[建構函數清單中](#constructor-parts)參考本機和全域組件。

如果您全域定義加密和簽章的組件清單，則必須提供建構組件清單，以識別複合信標可以組合複合信標組態中欄位的所有可能方式。

**注意**  
若要全域定義加密和已簽章的組件清單，您必須使用 3.2 版或更新版本的 AWS 資料庫加密 SDK。在全域定義任何新組件之前，將新版本部署到所有讀者。  
您無法更新現有的信標組態，以全域定義加密和已簽章的組件清單。

若要設定複合信標，請提供下列值。

**信標名稱**  
您在查詢加密欄位時使用的名稱。  
信標名稱可與加密欄位或虛擬欄位的名稱相同，但不能與未加密欄位的名稱相同。兩個信標不能有相同的信標名稱。如需判斷實作最佳信標名稱的說明，請參閱[選擇信標名稱](choosing-beacon-name.md)。

**分割字元**  
用來分隔組成複合信標之部分的字元。  
分割字元無法出現在複合信標建構來源之任何欄位的純文字值中。

**加密的組件清單**  
識別複合信標中包含`ENCRYPT_AND_SIGN`的欄位。  
每個部分都必須包含名稱和字首。部分名稱必須是從加密欄位建構的標準信標名稱。字首可以是任何字串，但必須是唯一的。加密的組件不能具有與已簽署組件相同的字首。建議使用短值來區分部分與複合信標提供的其他部分。  
我們建議您盡可能全域定義您的加密組件。如果您只打算在一個複合信標中使用加密部分，您可以考慮在本機定義加密部分。本機定義的加密部分不能具有與全域定義的加密部分相同的字首或名稱。  

```
List<EncryptedPart> encryptedPartList = new ArrayList<>();
EncryptedPart encryptedPartExample = EncryptedPart.builder()
    .name("standardBeaconName")
    .prefix("E-")
    .build();
encryptedPartList.add(encryptedPartExample);
```

```
var encryptedPartList = new List<EncryptedPart>();
var encryptedPartExample = new EncryptedPart
 {
    Name = "compoundBeaconName",
    Prefix = "E-"
 };
encryptedPartList.Add(encryptedPartExample);
```

```
let encrypted_parts_list = vec![
    EncryptedPart::builder()
        .name("standard_beacon_name")
        .prefix("E-")
        .build()?
];
```

**已簽章的組件清單**  
識別複合信標中包含的已簽章欄位。  
簽章部分是選用的。您可以設定不參考任何已簽章部分的複合信標。
每個部分都必須包含名稱、來源和字首。來源是組件識別的 `SIGN_ONLY`或 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 欄位。來源必須是參照巢狀欄位值的欄位名稱或索引。如果您的組件名稱識別來源，您可以省略來源， AWS 資料庫加密 SDK 會自動使用該名稱做為來源。我們建議您盡可能將來源指定為組件名稱。字首可以是任何字串，但必須是唯一的。已簽章的部分不能具有與已加密部分相同的字首。建議使用短值來區分部分與複合信標提供的其他部分。  
我們建議您盡可能全域定義您的已簽署組件。如果您只打算在一個複合信標中使用已簽署的組件，您可以考慮在本機定義該組件。本機定義的已簽章部分不能具有與全域定義的已簽章部分相同的字首或名稱。  

```
List<SignedPart> signedPartList = new ArrayList<>();
SignedPart signedPartExample = SignedPart.builder()
    .name("signedFieldName")
    .prefix("S-")
    .build();
signedPartList.add(signedPartExample);
```

```
var signedPartsList = new List<SignedPart>
{
    new SignedPart { Name = "signedFieldName1", Prefix = "S-" },
    new SignedPart { Name = "signedFieldName2", Prefix = "SF-" }
};
```

```
let signed_parts_list = vec![
    SignedPart::builder()
        .name("signed_field_name_1")
        .prefix("S-")
        .build()?,
   SignedPart::builder()
        .name("signed_field_name_2")
        .prefix("SF-")
        .build()?,     
];
```

**建構器清單**  
識別建構*函數*，這些建構函數定義了由複合信標組合加密和簽章組件的不同方式。您可以在建構函數清單中參考本機和全域組件。  
如果您從全域定義的加密和簽章組件建構複合信標，則必須提供建構器清單。  
如果您未使用任何全域定義的加密或簽章組件來建構複合信標，則建構器清單是選用的。如果您未指定建構函數清單， AWS 資料庫加密 SDK 會組合複合信標與下列預設建構函數。  
+ 所有已簽章組件依其新增至已簽章組件清單的順序進行
+ 依其新增至加密組件清單的順序排列的所有加密組件
+ 需要所有組件  
**建構函式**  
每個建構函數都是*建構函數組件*的排序清單，可定義複合信標的組合方式。建構函數部分會依新增至清單的順序聯結在一起，每個部分以指定的分割字元分隔。  
每個建構函數組件都會命名加密的組件或已簽章的組件，並定義該組件在建構函數中為必要或選用。例如，如果您想要在 `Field1`、 `Field1.Field2`和 上查詢複合信標`Field1.Field2.Field3`，請將 `Field2`和 標記為`Field3`選用，並建立一個建構函數。  
每個建構函數必須至少有一個必要的部分。我們建議您讓每個建構函數的第一部分成為必要項目，以便在查詢中使用`BEGINS_WITH`運算子。  
如果記錄中存在所有必要的組件，建構函數就會成功。當您撰寫新記錄時，複合信標會使用建構函數清單來判斷信標是否可以從提供的值組合。它會嘗試依建構函數新增至建構函數清單的順序組合信標，並使用第一個成功的建構函數。如果沒有建構函數成功，則不會將信標寫入記錄。  
所有讀者和寫入者都應指定相同的建構函數順序，以確保其查詢結果正確。
使用以下程序來指定您自己的建構函數清單。  

1. 為每個加密的組件和已簽章的組件建立建構組件，以定義是否需要該組件。

   建構函數部分名稱必須是其代表的標準信標或已簽章欄位的名稱。

------
#### [ Java ]

   ```
   ConstructorPart field1ConstructorPart = ConstructorPart.builder()
           .name("Field1")
           .required(true)
           .build();
   ```

------
#### [ C\$1 / .NET ]

   ```
   var field1ConstructorPart = new ConstructorPart { Name = "Field1", Required = true };
   ```

------
#### [ Rust ]

   ```
   let field_1_constructor_part = ConstructorPart::builder()
       .name("field_1")
       .required(true)
       .build()?;
   ```

------

1. 使用您在**步驟 1** 中建立的建構函式部分，為每個可能的複合信標組合方式建立建構函式。

   例如，如果您想要在 `Field1.Field2.Field3`和 上查詢 `Field4.Field2.Field3`，則必須建立兩個建構函數。 `Field1`和 `Field4`都可能是必要的，因為它們是在兩個不同的建構函數中定義。

------
#### [ Java ]

   ```
   // Create a list for Field1.Field2.Field3 queries
   List<ConstructorPart> field123ConstructorPartList = new ArrayList<>();
   field123ConstructorPartList.add(field1ConstructorPart);
   field123ConstructorPartList.add(field2ConstructorPart);
   field123ConstructorPartList.add(field3ConstructorPart);
   Constructor field123Constructor = Constructor.builder()
           .parts(field123ConstructorPartList)
           .build();
   // Create a list for Field4.Field2.Field1 queries
   List<ConstructorPart> field421ConstructorPartList = new ArrayList<>();
   field421ConstructorPartList.add(field4ConstructorPart);
   field421ConstructorPartList.add(field2ConstructorPart);
   field421ConstructorPartList.add(field1ConstructorPart);
   Constructor field421Constructor = Constructor.builder()
           .parts(field421ConstructorPartList)
           .build();
   ```

------
#### [ C\$1 / .NET ]

   ```
   // Create a list for Field1.Field2.Field3 queries
    var field123ConstructorPartList = new Constructor
   {
       Parts = new List<ConstructorPart> { field1ConstructorPart, field2ConstructorPart, field3ConstructorPart }
   };
   // Create a list for Field4.Field2.Field1 queries        
   var field421ConstructorPartList = new Constructor
   {
       Parts = new List<ConstructorPart> { field4ConstructorPart, field2ConstructorPart, field1ConstructorPart }
   };
   ```

------
#### [ Rust ]

   ```
   // Create a list for field1.field2.field3 queries
   let field1_field2_field3_constructor = Constructor::builder()
       .parts(vec![
           field1_constructor_part,
           field2_constroctor_part.clone(),
           field3_constructor_part,
       ])
       .build()?;
   
   // Create a list for field4.field2.field1 queries
   let field4_field2_field1_constructor = Constructor::builder()
       .parts(vec![
           field4_constructor_part,
           field2_constroctor_part.clone(),
           field1_constructor_part,
       ])
       .build()?;
   ```

------

1. 建立建構函數清單，其中包含您在**步驟 2** 中建立的所有建構函數。

------
#### [ Java ]

   ```
   List<Constructor> constructorList = new ArrayList<>();
   constructorList.add(field123Constructor);
   constructorList.add(field421Constructor);
   ```

------
#### [ C\$1 / .NET ]

   ```
   var constructorList = new List<Constructor>
   {
       field123Constructor,
       field421Constructor
   };
   ```

------
#### [ Rust ]

   ```
   let constructor_list = vec![
       field1_field2_field3_constructor,
       field4_field2_field1_constructor,
   ];
   ```

------

1. 當您建立複合信標`constructorList`時，請指定 。

# 範例組態
<a name="beacon-config-examples"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

下列範例示範如何設定標準和複合信標。下列組態不提供信標長度。如需判斷組態適當信標長度的說明，請參閱[選擇信標長度](choosing-beacon-length.md)。

若要查看示範如何設定和使用信標的完整程式碼範例，請參閱 GitHub 上 aws-database-encryption-sdk-dynamodb 儲存庫中的 [Java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption)、.[NET](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/) 和 [Rust](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/) 可搜尋加密範例。

**Topics**
+ [標準信標](#standard-config-examples)
+ [複合信標](#compound-config-examples)

## 標準信標
<a name="standard-config-examples"></a>

如果您想要查詢 `inspector_id_last4` 欄位是否完全相符，請使用下列組態建立標準信標。

------
#### [ Java ]

```
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon exampleStandardBeacon = StandardBeacon.builder()
    .name("inspector_id_last4")
    .length(beaconLengthInBits)
    .build();
standardBeaconList.add(exampleStandardBeacon);
```

------
#### [ C\$1 / .NET ]

```
var standardBeaconList = new List<StandardBeacon>>);
StandardBeacon exampleStandardBeacon = new StandardBeacon
  {
    Name = "inspector_id_last4",
    Length = 10
  };
standardBeaconList.Add(exampleStandardBeacon);
```

------
#### [ Rust ]

```
let last4_beacon = StandardBeacon::builder()
    .name("inspector_id_last4")
    .length(10)
    .build()?;
                        
let unit_beacon = StandardBeacon::builder().name("unit").length(30).build()?;

let standard_beacon_list = vec![last4_beacon, unit_beacon];
```

------

## 複合信標
<a name="compound-config-examples"></a>

如果您想要查詢 `inspector_id_last4`和 上的`UnitInspection`資料庫`inspector_id_last4.unit`，請使用下列組態建立複合信標。此複合信標只需要[加密的部分](configure-beacons.md#encrypted-parts)。

------
#### [ Java ]

```
// 1. Create standard beacons for the inspector_id_last4 and unit fields.
List<StandardBeacon> standardBeaconList = new ArrayList<>();
StandardBeacon inspectorBeacon = StandardBeacon.builder()
    .name("inspector_id_last4")
    .length(beaconLengthInBits)
    .build();
standardBeaconList.add(inspectorBeacon);

StandardBeacon unitBeacon = StandardBeacon.builder()
    .name("unit")
    .length(beaconLengthInBits)
    .build();
standardBeaconList.add(unitBeacon);        

// 2. Define the encrypted parts.
List<EncryptedPart> encryptedPartList = new ArrayList<>();

// Each encrypted part needs a name and prefix
// The name must be the name of the standard beacon
// The prefix must be unique
// For this example we use the prefix "I-" for "inspector_id_last4"
// and "U-" for "unit"
EncryptedPart encryptedPartInspector = EncryptedPart.builder()
    .name("inspector_id_last4")
    .prefix("I-")
    .build();
encryptedPartList.add(encryptedPartInspector);

EncryptedPart encryptedPartUnit = EncryptedPart.builder()
    .name("unit")
    .prefix("U-")
    .build();
encryptedPartList.add(encryptedPartUnit);   

// 3. Create the compound beacon.
// This compound beacon only requires a name, split character, 
// and list of encrypted parts
CompoundBeacon inspectorUnitBeacon = CompoundBeacon.builder()
    .name("inspectorUnitBeacon")
    .split(".")
    .sensitive(encryptedPartList)
    .build();
```

------
#### [ C\$1 / .NET ]

```
// 1. Create standard beacons for the inspector_id_last4 and unit fields.
StandardBeacon inspectorBeacon = new StandardBeacon
 {
   Name = "inspector_id_last4",
   Length = 10
 };
standardBeaconList.Add(inspectorBeacon);
StandardBeacon unitBeacon = new StandardBeacon
 {
    Name = "unit",
    Length = 30
 };  
standardBeaconList.Add(unitBeacon);
                
// 2. Define the encrypted parts.
var last4EncryptedPart = new EncryptedPart

// Each encrypted part needs a name and prefix
// The name must be the name of the standard beacon
// The prefix must be unique
// For this example we use the prefix "I-" for "inspector_id_last4"
// and "U-" for "unit"
var last4EncryptedPart = new EncryptedPart
 {
   Name = "inspector_id_last4",
   Prefix = "I-"
 };
encryptedPartList.Add(last4EncryptedPart);

var unitEncryptedPart = new EncryptedPart
 {
   Name = "unit",
   Prefix = "U-"
 };
encryptedPartList.Add(unitEncryptedPart); 

// 3. Create the compound beacon.
// This compound beacon only requires a name, split character, 
// and list of encrypted parts
var compoundBeaconList = new List<CompoundBeacon>>);
var inspectorCompoundBeacon = new CompoundBeacon
  {
      Name = "inspector_id_last4",
      Split = ".",
      Encrypted = encryptedPartList
  };
compoundBeaconList.Add(inspectorCompoundBeacon);
```

------
#### [ Rust ]

```
// 1. Create standard beacons for the inspector_id_last4 and unit fields.
let last4_beacon = StandardBeacon::builder()
    .name("inspector_id_last4")
    .length(10)
    .build()?;
                        
let unit_beacon = StandardBeacon::builder().name("unit").length(30).build()?;

let standard_beacon_list = vec![last4_beacon, unit_beacon];
                        
// 2. Define the encrypted parts.
// The name must be the name of the standard beacon
// The prefix must be unique
// For this example we use the prefix "I-" for "inspector_id_last4"
// and "U-" for "unit"
let encrypted_parts_list = vec![
    EncryptedPart::builder()
        .name("inspector_id_last4")
        .prefix("I-")
        .build()?,
    EncryptedPart::builder().name("unit").prefix("U-").build()?,
];

// 3. Create the compound beacon
// This compound beacon only requires a name, split character, 
// and list of encrypted parts
let compound_beacon_list = vec![CompoundBeacon::builder()
    .name("last4UnitCompound")
    .split(".")
    .encrypted(encrypted_parts_list)
    .build()?];
```

------

# 使用信標
<a name="using-beacons"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

Beacons 可讓您搜尋加密的記錄，而不會解密要查詢的整個資料庫。信標設計為在新的未填入資料庫中實作。在現有資料庫中設定的任何信標只會映射寫入資料庫的新記錄。信標是根據欄位的純文字值計算，一旦欄位加密，信標就無法映射現有資料。使用信標撰寫新記錄之後，您就無法更新信標的組態。不過，您可以為新增至記錄的新欄位新增新信標。

設定信標之後，您必須先完成下列步驟，才能開始填入資料庫並對信標執行查詢。

1. **建立 AWS KMS 階層 keyring**

   若要使用可搜尋加密，您必須使用[AWS KMS 階層式 keyring](use-hierarchical-keyring.md) 來產生、加密和解密用於保護記錄[的資料金鑰](concepts.md#data-key)。

   設定信標之後，請組合[階層式 keyring 先決條件](use-hierarchical-keyring.md#hierarchical-keyring-prereqs)並[建立階層式 keyring](use-hierarchical-keyring.md#initialize-hierarchical-keyring)。

   如需為何需要階層式 keyring 的詳細資訊，請參閱[使用階層式 keyring 進行可搜尋加密](use-hierarchical-keyring.md#searchable-encryption-hierarchical-keyrings)。

1. 

   **定義信標版本 **

   指定您的 `keyStore`、`keySource`、您設定的所有標準信標清單、您設定的所有複合信標清單、加密組件清單、已簽署組件清單，以及信標版本。您必須`1`為信標版本指定 。如需定義 的指引`keySource`，請參閱 [定義您的信標金鑰來源](use-hierarchical-keyring.md#beacon-key-source)。

   下列 Java 範例定義單一租戶資料庫的信標版本。如需定義多租戶資料庫信標版本的說明，請參閱[多租戶資料庫的可搜尋加密](searchable-encryption-multitenant.md)。

------
#### [ Java ]

   ```
    List<BeaconVersion> beaconVersions = new ArrayList<>();
   beaconVersions.add(
       BeaconVersion.builder()
           .standardBeacons(standardBeaconList)
           .compoundBeacons(compoundBeaconList)
           .encryptedParts(encryptedPartsList)
           .signedParts(signedPartsList)
           .version(1) // MUST be 1
           .keyStore(keyStore)
           .keySource(BeaconKeySource.builder()
               .single(SingleKeyStore.builder()
                   .keyId(branchKeyId)
                   .cacheTTL(6000)
                   .build())
               .build())
           .build()
   );
   ```

------
#### [ C\$1 / .NET ]

   ```
   var beaconVersions = new List<BeaconVersion>
   {
       new BeaconVersion
       {
           StandardBeacons = standardBeaconList,
           CompoundBeacons = compoundBeaconList,
           EncryptedParts = encryptedPartsList,
           SignedParts = signedPartsList,
           Version = 1, // MUST be 1
           KeyStore = branchKeyStoreName,
           KeySource = new BeaconKeySource
           {
               Single = new SingleKeyStore
               {
                   KeyId = branch-key-id,
                   CacheTTL = 6000
               }
           }
       }
   };
   ```

------
#### [ Rust ]

   ```
   let beacon_version = BeaconVersion::builder()
       .standard_beacons(standard_beacon_list)
       .compound_beacons(compound_beacon_list)
       .version(1) // MUST be 1
       .key_store(key_store.clone())
       .key_source(BeaconKeySource::Single(
           SingleKeyStore::builder()
               // `keyId` references a beacon key.
               // For every branch key we create in the keystore,
               // we also create a beacon key.
               // This beacon key is not the same as the branch key,
               // but is created with the same ID as the branch key.
               .key_id(branch_key_id)
               .cache_ttl(6000)
               .build()?,
       ))
       .build()?;
   let beacon_versions = vec![beacon_version];
   ```

------

1. **設定次要索引**

   [設定信標](configure-beacons.md)之後，您必須先設定反映每個信標的次要索引，才能搜尋加密的欄位。如需詳細資訊，請參閱[使用信標設定次要索引](ddb-searchable-encryption.md#ddb-beacon-indexes)。

1. **定義您的[密碼編譯動作](concepts.md#crypt-actions)**

   用於建構標準信標的所有欄位都必須標記為 `ENCRYPT_AND_SIGN`。用於建構信標的所有其他欄位都必須標示 `SIGN_ONLY`或 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

1. **設定 AWS 資料庫加密 SDK 用戶端**

   若要設定 Database AWS Encryption SDK 用戶端來保護 DynamoDB 資料表中的資料表項目，請參閱適用於 [ DynamoDB 的 Java 用戶端加密程式庫](ddb-java.md)。

## 查詢信標
<a name="querying-beacons"></a>

您設定的信標類型會決定您可以執行的查詢類型。標準信標使用篩選條件表達式來執行等式搜尋。複合信標結合常值純文字字串和標準信標，以執行複雜的查詢。當您查詢加密的資料時，您會搜尋信標名稱。

您無法比較兩個標準信標的值，即使它們包含相同的基礎純文字。兩個標準信標將為相同的純文字值產生兩個不同的 HMAC 標籤。因此，標準信標無法執行下列查詢。
+ `beacon1 = beacon2`
+ `beacon1 IN (beacon2)`
+ `value IN (beacon1, beacon2, ...)`
+ `CONTAINS(beacon1, beacon2)`

複合信標可以執行下列查詢。
+ `BEGINS_WITH(a)`，其中 `a`會反映組合複合信標開頭之欄位的整個值。您無法使用 `BEGINS_WITH`運算子來識別以特定子字串開頭的值。不過，您可以使用 `BEGINS_WITH(S_)`，其中 `S_`會反映組合複合信標開頭的部分字首。
+ `CONTAINS(a)`，其中 `a`會反映組合複合信標包含之欄位的整個值。您無法使用 `CONTAINS`運算子來識別包含特定子字串或集合內值的記錄。

  例如，您無法執行查詢，`CONTAINS(path, "a"`其中 `a`會反映集合中的值。
+ 您可以比較複合信標的[簽章部分](configure-beacons.md#signed-parts)。當您比較已簽章的組件時，您可以選擇將[已加密組件](configure-beacons.md#encrypted-parts)的字首附加至一或多個已簽章的組件，但您無法在任何查詢中包含已加密欄位的值。

  例如，您可以在 `signedField1 = signedField2`或 上比較已簽章的組件和查詢`value IN (signedField1, signedField2, ...)`。

  您也可以在 上查詢，比較已簽章的組件和已加密組件的字首`signedField1.A_ = signedField2.B_`。
+ `field BETWEEN a AND b`，其中 `a`和 `b`是帶正負號的部分。您可以選擇將加密部分的字首附加至一或多個已簽章的組件，但您無法在任何查詢中包含加密欄位的值。

您必須在複合信標的查詢中包含每個部分的字首。例如，如果您從`compoundBeacon`兩個欄位 `encryptedField`和 建構複合信標 `signedField`，則必須在查詢信標時包含為這兩個部分設定的字首。

```
compoundBeacon = E_encryptedFieldValue.S_signedFieldValue
```

# 多租戶資料庫的可搜尋加密
<a name="searchable-encryption-multitenant"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

若要在資料庫中實作可搜尋的加密，您必須使用[AWS KMS 階層式 keyring](use-hierarchical-keyring.md)。 AWS KMS 階層式 keyring 會產生、加密和解密用於保護記錄的資料金鑰。它也會建立用來產生信標的信標金鑰。搭配多租用戶資料庫使用 AWS KMS 階層式 keyring 時，每個租用戶都有不同的分支金鑰和信標金鑰。若要查詢多租戶資料庫中的加密資料，您必須識別用來產生您正在查詢之信標的信標金鑰資料。如需詳細資訊，請參閱[使用階層式 keyring 進行可搜尋的加密](use-hierarchical-keyring.md#searchable-encryption-hierarchical-keyrings)。

當您定義多租戶資料庫的[信標版本](using-beacons.md#beacon-version)時，請指定您設定的所有標準信標清單、您設定的所有複合信標清單、信標版本和 `keySource`。您必須將[信標金鑰來源定義為](use-hierarchical-keyring.md#beacon-key-source) `MultiKeyStore`，並包含 `keyFieldName`、本機信標金鑰快取的存留時間，以及本機信標金鑰快取的快取大小上限。

如果您設定了任何[已簽章的信標](configure.md#signed-beacons)，它們必須包含在您的 中`compoundBeaconList`。簽章信標是一種複合信標，可對 `SIGN_ONLY` 和 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`欄位編製索引並執行複雜的查詢。

------
#### [ Java ]

```
List<BeaconVersion> beaconVersions = new ArrayList<>();
    beaconVersions.add(
        BeaconVersion.builder()
                .standardBeacons(standardBeaconList)
                .compoundBeacons(compoundBeaconList)
                .version(1) // MUST be 1
                .keyStore(branchKeyStoreName)
                .keySource(BeaconKeySource.builder()
                        .multi(MultiKeyStore.builder()
                                .keyFieldName(keyField)
                                .cacheTTL(6000)
                                .maxCacheSize(10)
                        .build())
                .build())
        .build()
    );
```

------
#### [ C\$1 / .NET ]

```
var beaconVersions = new List<BeaconVersion>
{
    new BeaconVersion
    {
        StandardBeacons = standardBeaconList,
        CompoundBeacons = compoundBeaconList,
        EncryptedParts = encryptedPartsList,
        SignedParts = signedPartsList,
        Version = 1, // MUST be 1
        KeyStore = branchKeyStoreName,
        KeySource = new BeaconKeySource
        {
            Multi = new MultiKeyStore
            {
                KeyId = branch-key-id,
                CacheTTL = 6000,
                MaxCacheSize = 10
            }
        }
    }
};
```

------
#### [ Rust ]

```
let beacon_version = BeaconVersion::builder()
    .standard_beacons(standard_beacon_list)
    .compound_beacons(compound_beacon_list)
    .version(1) // MUST be 1
    .key_store(key_store.clone())
    .key_source(BeaconKeySource::Multi(
        MultiKeyStore::builder()
            // `keyId` references a beacon key.
            // For every branch key we create in the keystore,
            // we also create a beacon key.
            // This beacon key is not the same as the branch key,
            // but is created with the same ID as the branch key.
            .key_id(branch_key_id)
            .cache_ttl(6000)
            .max_cache_size(10)
            .build()?,
    ))
    .build()?;
let beacon_versions = vec![beacon_version];
```

------

**keyFieldName**  
[`keyFieldName`](use-hierarchical-keyring.md#keyFieldName) 定義 欄位的名稱，該欄位存放與用於為指定租用戶產生信標的信標金鑰`branch-key-id`相關聯的 。  
當您將新記錄寫入資料庫時，識別用於為該記錄產生任何信標的`branch-key-id`信標金鑰的 會存放在此欄位中。  
根據預設， `keyField`是概念性欄位，不會明確存放在您的資料庫中。 AWS Database Encryption SDK `branch-key-id`會從[材料描述](concepts.md#material-description)中的加密[資料金鑰](concepts.md#data-key)識別 ，並將值存放在概念中，`keyField`供您在複合信標和[簽章信標](configure.md#signed-beacons)中參考。由於材料描述已簽署，因此概念`keyField`會被視為已簽署部分。  
您也可以將 作為 `SIGN_ONLY`或 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 欄位包含在密碼編譯動作`keyField`中，以明確將 欄位存放在資料庫中。如果您這樣做，`keyField`每次將記錄寫入資料庫時，都必須手動將 包含在 `branch-key-id`中。

## 查詢多租戶資料庫中的信標
<a name="query-multitenant-beacons"></a>

若要查詢信標，您必須在查詢`keyField`中包含 ，以識別重新計算信標所需的適當信標金鑰資料。您必須指定與用來產生記錄信標的信標金鑰`branch-key-id`相關聯的 。您無法在分支金鑰 ID 供應商`branch-key-id`中指定識別租戶的[易記名稱](use-hierarchical-keyring.md#branch-key-id-supplier)。您可以透過下列方式將 包含在查詢`keyField`中。

**複合信標**  
無論您是否明確`keyField`將 存放在記錄中，都可以將 `keyField` 直接包含在複合信標中，做為已簽章的部分。`keyField` 簽署的部分必須是必要項目。  
例如，如果您想要`compoundBeacon`從兩個欄位 `encryptedField`和 建構複合信標 ，`signedField`您也必須包含 `keyField`做為已簽章的部分。這可讓您在 上執行下列查詢`compoundBeacon`。  

```
compoundBeacon = E_encryptedFieldValue.S_signedFieldValue.K_branch-key-id
```

**已簽章的信標**  
 AWS Database Encryption SDK 使用標準和複合信標來提供可搜尋的加密解決方案。這些信標必須至少包含一個加密欄位。不過， AWS 資料庫加密 SDK 也支援[簽署的信標](configure.md#signed-beacons)，這些信標可以完全從純文字`SIGN_ONLY`和`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`欄位設定。  
已簽章的信標可以從單一部分建構。無論您是否明確`keyField`將 存放在記錄中，都可以從 建構已簽章的信標，`keyField`並使用它來建立複合查詢，將`keyField`已簽章信標上的查詢與其中一個信標上的查詢結合在一起。例如，您可以執行下列查詢。  

```
keyField = K_branch-key-id AND compoundBeacon = E_encryptedFieldValue.S_signedFieldValue
```
如需設定簽章信標的說明，請參閱 [建立簽章的信標](configure.md#signed-beacons)

**直接在 上查詢 `keyField`**  
如果您在密碼編譯動作`keyField`中指定 ，並明確將 欄位存放在記錄中，您可以建立複合查詢，將信標上的查詢與 上的查詢結合在一起`keyField`。`keyField` 如果您想要查詢標準信標，您可以選擇直接在 上查詢。例如，您可以執行下列查詢。  

```
keyField = branch-key-id AND standardBeacon = S_standardBeaconValue
```