

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

# 第 3 版中的 Amazon S3 加密用戶端遷移 (V2 到 V3) 適用於 PHP 的 AWS SDK
<a name="s3-encryption-migration-v2-v3"></a>

**注意**  
如果您使用的是 Amazon S3 加密用戶端的第 1 版 (V1)，您必須先遷移到第 2 版 (V2)，然後再遷移到第 3 版 (V3)。請參閱 [第 3 版中的 Amazon S3 加密用戶端遷移 (V1 到 V2) 適用於 PHP 的 AWS SDK](s3-encryption-migration-v1-v2.md)。

本主題說明如何將應用程式從 Amazon Simple Storage Service (Amazon S3) 加密用戶端的第 2 版 (V2) 遷移到第 3 版 (V3)，並確保在整個遷移過程中的應用程式可用性。第 3 版推出具有金鑰承諾和承諾政策的 AES GCM，以增強安全性並防止資料金鑰竄改。

## 遷移概觀
<a name="s3-encryption-migration-v2-v3-overview"></a>

此遷移分為兩個階段：

1. **更新現有用戶端以讀取新格式。**首先，將更新的 適用於 PHP 的 AWS SDK 版本部署到您的應用程式。這可讓現有的 V2 加密用戶端解密新 V3 用戶端寫入的物件。如果您的應用程式使用多個 AWS SDKs，您必須分別升級每個 SDK。

2. **將加密和解密用戶端遷移至 V3。**一旦所有 V2 加密用戶端都可以讀取新的格式，您就可以將現有的加密和解密用戶端遷移到各自的 V3 版本。

## 了解 V3 概念
<a name="s3-encryption-migration-v2-v3-concepts"></a>

Amazon S3 加密用戶端第 3 版推出兩個金鑰安全性增強功能：承諾政策和具有金鑰承諾演算法的 AES GCM。了解這些概念對於成功遷移至關重要。

### 承諾政策
<a name="s3-encryption-migration-v2-v3-concepts-commitment-policy"></a>

承諾政策控制加密用戶端在加密和解密操作期間處理金鑰承諾的方式。第 3 版提供三種政策選項：

`FORBID_ENCRYPT_ALLOW_DECRYPT`  
**加密行為：**在沒有金鑰承諾的情況下加密物件。  
**解密行為：**允許解密有或沒有金鑰承諾的加密物件。  
**安全性影響：**此政策不會對新加密的物件強制執行金鑰承諾，這可能允許資料金鑰竄改。當您需要維持與 V2 用戶端的相容性時，請僅在初始遷移階段使用此政策。  
**版本相容性：**所有 V2 和 V3 實作都可以讀取使用此政策加密的物件。

`REQUIRE_ENCRYPT_ALLOW_DECRYPT`  
**加密行為：**使用`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`演算法加密具有金鑰承諾的物件。  
**解密行為：**允許解密有或沒有金鑰承諾的加密物件。  
**安全性影響：**此政策為新加密的物件提供增強的安全性，同時維持讀取現有物件的能力。這是大多數遷移案例的建議政策。  
**版本相容性：**使用此政策加密的物件只能由 V3 和最新的 V2 實作讀取。  
**遷移考量：**使用此政策之前，請確保需要讀取加密物件的所有用戶端都已升級至 V3 或最新的 V2。

`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`  
**加密行為：**使用`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`演算法加密具有金鑰承諾的物件。  
**解密行為：**僅允許解密以金鑰承諾加密的物件。在沒有金鑰承諾的情況下加密的物件將無法解密。  
**安全性影響：**此政策透過強制執行加密和解密的金鑰承諾，提供最高層級的安全性。只有在遷移所有物件以使用金鑰承諾之後，才使用此政策。  
**版本相容性：**只有 V3 實作可以使用此政策。嘗試使用此政策解密 V1 或 V2 加密物件將會失敗。  
**遷移考量：**只有在完成完整遷移，並使用金鑰承諾重新加密所有現有物件之後，才能使用此政策。

### 具有金鑰承諾的 AES GCM
<a name="s3-encryption-migration-v2-v3-concepts-aes-gcm-kc"></a>

AES GCM 與金鑰承諾 (`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`) 演算法是 V3 中引入的新加密演算法，可保護資料金鑰免受竄改攻擊。

**安全增強功能：**以密碼編譯方式將資料金鑰繫結至加密的內容，`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`以防止資料金鑰遭到竄改。這可防止攻擊者在解密期間替換不同的資料金鑰，這可能會導致意外資料解密。

**版本相容性：**使用 加密的物件`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`只能由 V3 加密用戶端的 V3 和最新的 V2 實作解密。 Amazon S3 V1 用戶端無法解密使用此演算法加密的物件。

**重要**  
**升級需求：**啟用 加密之前 `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`（使用 REQUIRE\_ENCRYPT\_ALLOW\_DECRYPT 或 REQUIRE\_ENCRYPT\_REQUIRE\_DECRYPT 政策），您必須確保所有需要讀取加密物件的用戶端都已升級至 V3。無法升級所有讀取器會導致使用金鑰承諾加密的物件發生解密失敗。

## 更新現有用戶端以讀取新格式
<a name="s3-encryption-migration-v2-v3-update-clients"></a>

V3 加密用戶端使用舊版用戶端不支援的加密演算法和金鑰承諾功能。遷移的第一步是將 V2 解密用戶端更新為最新的 SDK 版本。完成此步驟後，應用程式的 V2 用戶端將能夠解密由 V3 加密用戶端加密的物件。請參閱以下有關 的每個安裝方法的詳細資訊 適用於 PHP 的 AWS SDK。

### 建置和安裝最新的 SDK 版本
<a name="s3-encryption-migration-v2-v3-update-clients-sdk"></a>

若要完成此遷移，您必須使用包含 V3 加密用戶端支援的最新版本 `aws/aws-sdk-php`套件。

 **從 Composer 安裝** 

對於使用 Composer 安裝的專案，請在 Composer 檔案中，將 SDK 套件更新為最新版本的 SDK，然後執行下列命令。

```
composer update aws/aws-sdk-php
```

 **使用 Phar 或 Zip 檔案安裝** 

使用下列其中一種方法。請務必將更新的 SDK 檔案放在程式碼所需的位置，此位置由 要求陳述式決定。

對於使用 Phar 檔案安裝的專案，請下載更新的 檔案：[`aws.phar`](https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.phar)。

```
<?php
  require '/path/to/aws.phar';
?>
```

對於使用 Zip 檔案安裝的專案，請下載更新的 檔案：[``](https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.zip)。

```
<?php
  require '/path/to/aws-autoloader.php';
?>
```

### 建置、安裝和部署應用程式
<a name="s3-encryption-migration-v2-v3-update-clients-deploy"></a>

更新軟體開發套件後，請重建並重新部署您的應用程式，以確保所有元件都使用更新版本。此步驟對於確保您的 V2 用戶端可以讀取 V3 用戶端加密的物件至關重要。

請遵循組織的標準部署程序來推出更新的應用程式。在繼續將您的加密和解密用戶端遷移至 V3 之前，請確定應用程式的所有執行個體都已更新。

部署之後，請確認您的應用程式仍然可以解密現有的物件，而且在正常操作期間不會發生錯誤。這可確認 SDK 更新成功，而且您的應用程式已準備好進行下一個階段的遷移。

## 將加密和解密用戶端遷移至 V3
<a name="s3-encryption-migration-v2-v3-migrate"></a>

將用戶端更新為讀取新的加密格式後，您可以將應用程式更新為 V3 加密和解密用戶端。下列範例示範如何成功將程式碼從 V2 遷移至 V3。

### 使用 V3 加密用戶端
<a name="s3-encryption-migration-v2-v3-using-v3-clients"></a>

V3 引入 `S3EncryptionClientV3`類別，並`KmsMaterialsProviderV3`取代 V2 對等項目。V3 中的主要差異為：
+ V3 使用 `KmsMaterialsProviderV3`（與 V2 相同），但在`GetObject`呼叫中解密物件時驗證加密內容。
+ V3 推出承諾政策來控制加密和解密行為。

 **範例：使用 KMS 加密從 V2 遷移至 V3 ** 

 *預遷移 (V2)* 

```
use Aws\S3\Crypto\S3EncryptionClientV2;
use Aws\S3\S3Client;
use Aws\Crypto\KmsMaterialsProviderV2;
use Aws\Kms\KmsClient;

$encryptionClient = new S3EncryptionClientV2(
   new S3Client([
      'profile' => 'default',
      'region' => 'us-east-1',
      'version' => 'latest',
   ])
);

$kmsKeyId = 'kms-key-id';
$materialsProvider = new KmsMaterialsProviderV2(
   new KmsClient([
      'profile' => 'default',
      'region' => 'us-east-1',
      'version' => 'latest',
   ]),
   $kmsKeyId
);

$bucket = 'the-bucket-name';
$key = 'the-file-name';
$cipherOptions = [
   'Cipher' => 'gcm',
   'KeySize' => 256,
];

$encryptionClient->putObject([
   '@MaterialsProvider' => $materialsProvider,
   '@CipherOptions' => $cipherOptions,
   '@KmsEncryptionContext' => ['context-key' => 'context-value'],
   'Bucket' => $bucket,
   'Key' => $key,
   'Body' => fopen('file-to-encrypt.txt', 'r'),
]);

$result = $encryptionClient->getObject([
   '@KmsAllowDecryptWithAnyCmk' => true,
   '@SecurityProfile' => 'V2_AND_LEGACY',
   '@CommitmentPolicy' => 'FORBID_ENCRYPT_ALLOW_DECRYPT',
   '@MaterialsProvider' => $materialsProvider,
   '@CipherOptions' => $cipherOptions,
   'Bucket' => $bucket,
   'Key' => $key,
]);
```

 *在遷移期間 （具有回溯相容性的 V3)* 

```
use Aws\S3\Crypto\S3EncryptionClientV3;
use Aws\S3\S3Client;
use Aws\Crypto\KmsMaterialsProviderV3;
use Aws\Kms\KmsClient;

// Create V3 encryption client
$encryptionClient = new S3EncryptionClientV3(
   new S3Client([
      'profile' => 'default',
      'region' => 'us-east-1',
      'version' => 'latest',
   ])
);

// Create encryption materials
$kmsKeyId = 'kms-key-id';
$materialsProvider = new KmsMaterialsProviderV3(
   new KmsClient([
      'profile' => 'default',
      'region' => 'us-east-1',
      'version' => 'latest',
   ]),
   $kmsKeyId
);

$bucket = 'the-bucket-name';
$key = 'the-file-name';
$cipherOptions = [
   'Cipher' => 'gcm',
   'KeySize' => 256,
];

$encryptionClient->putObject([
   '@MaterialsProvider' => $materialsProvider,
   '@CipherOptions' => $cipherOptions,
   '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT',
   '@KmsEncryptionContext' => ['context-key' => 'context-value'],
   'Bucket' => $bucket,
   'Key' => $key,
   'Body' => fopen('file-to-encrypt.txt', 'r'),
]);

$result = $encryptionClient->getObject([
   '@SecurityProfile' => 'V3_AND_LEGACY',
   '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT',
   '@MaterialsProvider' => $materialsProvider,
   '@CipherOptions' => $cipherOptions,
   'Bucket' => $bucket,
   'Key' => $key,
]);
```

 *遷移後 (V3 與金鑰承諾）* 

```
use Aws\S3\Crypto\S3EncryptionClientV3;
use Aws\S3\S3Client;
use Aws\Crypto\KmsMaterialsProviderV3;
use Aws\Kms\KmsClient;
 
// Create V3 encryption client
$encryptionClient = new S3EncryptionClientV3(
   new S3Client([
      'profile' => 'default',
      'region' => 'us-east-1',
      'version' => 'latest',
   ])
);

// Create encryption materials
$kmsKeyId = 'kms-key-id';
$materialsProvider = new KmsMaterialsProviderV3(
   new KmsClient([
      'profile' => 'default',
      'region' => 'us-east-1',
      'version' => 'latest',
   ]),
   $kmsKeyId
);

$bucket = 'the-bucket-name';
$key = 'the-file-name';
$cipherOptions = [
   'Cipher' => 'gcm',
   'KeySize' => 256,
];

$encryptionClient->putObject([
   '@MaterialsProvider' => $materialsProvider,
   '@CipherOptions' => $cipherOptions,
   // Use the commitment policy (REQUIRE_ENCRYPT_REQUIRE_DECRYPT)
   // This encrypts with key commitment and does not decrypt V2 objects
   '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
   '@KmsEncryptionContext' => ['context-key' => 'context-value'],
   'Bucket' => $bucket,
   'Key' => $key,
   'Body' => fopen('file-to-encrypt.txt', 'r'),
]);

$result = $encryptionClient->getObject([
   '@SecurityProfile' => 'V3',
   // Use the commitment policy (REQUIRE_ENCRYPT_REQUIRE_DECRYPT)
   // This encrypts with key commitment and does not decrypt V2 objects
   '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
   '@MaterialsProvider' => $materialsProvider,
   '@CipherOptions' => $cipherOptions,
   'Bucket' => $bucket,
   'Key' => $key,
]);
```

V3 中的主要差異：
+ 使用 `KmsMaterialsProviderV3` 而非 `KmsMaterialsProviderV2`
+ `putObject` 操作仍然需要 `@KmsEncryptionContext` 參數
+ `@KmsEncryptionContext` 參數對於 `getObject`操作是選用的，並會驗證提供的加密內容是否與 物件中的加密內容相符。
+ `@SecurityProfile` 參數控制哪些加密版本可以解密。設定為 `'V3_AND_LEGACY'`以支援在遷移期間讀取 V1 和 V2 加密物件
+ `@CommitmentPolicy` 參數控制此操作的承諾政策。設定為 `'FORBID_ENCRYPT_ALLOW_DECRYPT'`以支援在遷移期間讀取非承諾加密物件

## 其他範例
<a name="s3-encryption-migration-v2-v3-examples"></a>

下列範例示範 V3 中可用的其他組態選項，可協助您管理遷移程序和控制加密行為。

### 啟用舊版 支援
<a name="s3-encryption-migration-v2-v3-examples-legacy"></a>

在遷移期間，您可能需要解密使用 Amazon S3 加密用戶端的 V1 或 V2 加密的物件。`@SecurityProfile` 參數控制 V3 用戶端可以解密的加密版本。

**何時使用此組態：**當您的應用程式需要讀取 V1 或 V2 用戶端加密的物件時，請使用`'V3_AND_LEGACY'`安全性設定檔。當您的儲存貯體中混合了新的舊加密物件時，這在遷移期間很常見。

```
use Aws\S3\Crypto\S3EncryptionClientV3;
use Aws\S3\S3Client;
use Aws\Crypto\KmsMaterialsProviderV3;
use Aws\Kms\KmsClient;

$kmsKeyId = 'kms-key-id';
$materialsProvider = new KmsMaterialsProviderV3(
    new KmsClient([
        'profile' => 'default',
        'region' => 'us-east-1',
        'version' => 'latest',
    ]),
    $kmsKeyId
);

$encryptionClient = new S3EncryptionClientV3(
    new S3Client([
        'profile' => 'default',
        'region' => 'us-east-1',
        'version' => 'latest',
    ])
);

$bucket = 'the-bucket-name';
$key = 'the-file-name';
$cipherOptions = [
    'Cipher' => 'gcm',
    'KeySize' => 256,
];

// Decrypt objects encrypted with V1, V2, or V3
$result = $encryptionClient->getObject([
    '@SecurityProfile' => 'V3_AND_LEGACY',
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT',
    '@MaterialsProvider' => $materialsProvider,
    '@CipherOptions' => $cipherOptions,
    'Bucket' => $bucket,
    'Key' => $key,
]);
```

`@SecurityProfile` 參數接受下列值：
+ `'V3'` （預設）：僅使用金鑰承諾來解密使用 V3 加密的物件
+ `'V3_AND_LEGACY'`：解密使用 V1、V2 或 V3 加密的物件

**重要**  
完成遷移並使用 V3 重新加密所有物件之後，您應該移除 `@SecurityProfile` 參數或將其設定為 `'V3'` ，以確保最大安全性。

### 設定儲存方法
<a name="s3-encryption-migration-v2-v3-examples-storage"></a>

Amazon S3 加密用戶端可以透過兩種方式存放加密中繼資料：在物件的中繼資料標頭或單獨的指令檔案中。`@MetadataStrategy` 參數控制使用的儲存方法。

**何時使用此組態：**`'INSTRUCTION_FILE'`當您需要保留原始物件中繼資料，或使用具有中繼資料大小限制的物件時，請使用 。使用 `'METADATA'`（預設值） 進行更簡單的部署，其中加密中繼資料可以與物件一起存放。

```
use Aws\S3\Crypto\S3EncryptionClientV3;
use Aws\S3\S3Client;
use Aws\Crypto\KmsMaterialsProviderV3;
use Aws\Kms\KmsClient;

$kmsKeyId = 'kms-key-id';
$materialsProvider = new KmsMaterialsProviderV3(
    new KmsClient([
        'profile' => 'default',
        'region' => 'us-east-1',
        'version' => 'latest',
    ]),
    $kmsKeyId
);

$encryptionClient = new S3EncryptionClientV3(
    new S3Client([
        'profile' => 'default',
        'region' => 'us-east-1',
        'version' => 'latest',
    ])
);

$bucket = 'the-bucket-name';
$key = 'the-file-name';
$cipherOptions = [
    'Cipher' => 'gcm',
    'KeySize' => 256,
];

// Store encryption metadata in a separate instruction file
$encryptionClient->putObject([
    '@MaterialsProvider' => $materialsProvider,
    '@CipherOptions' => $cipherOptions,
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
    '@MetadataStrategy' => 'INSTRUCTION_FILE',
    '@KmsEncryptionContext' => ['context-key' => 'context-value'],
    'Bucket' => $bucket,
    'Key' => $key,
    'Body' => fopen('file-to-encrypt.txt', 'r'),
]);

// Store encryption metadata in object headers (default)
$encryptionClient->putObject([
    '@MaterialsProvider' => $materialsProvider,
    '@CipherOptions' => $cipherOptions,
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
    '@MetadataStrategy' => 'METADATA',
    '@KmsEncryptionContext' => ['context-key' => 'context-value'],
    'Bucket' => $bucket,
    'Key' => $key,
    'Body' => fopen('file-to-encrypt.txt', 'r'),
]);
```

`@MetadataStrategy` 參數接受下列值：
+ `'METADATA'` （預設）：將加密中繼資料儲存在物件的中繼資料標頭中
+ `'INSTRUCTION_FILE'`：使用尾碼將加密中繼資料存放在單獨的指令檔案中 `.instruction`

**注意**  
使用 時`'INSTRUCTION_FILE'`，AES GCM 與金鑰承諾演算法提供額外的保護，防止資料金鑰遭到竄改。使用`'METADATA'`儲存體的物件不會受益於此額外保護。