适用于 PHP 的 AWS SDK 版本 3 中的 Amazon S3 加密客户端迁移(从 V2 到 V3) - 适用于 PHP 的 AWS SDK

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

适用于 PHP 的 AWS SDK 版本 3 中的 Amazon S3 加密客户端迁移(从 V2 到 V3)

注意

如果您使用的是 Amazon S3 加密客户端的版本 1 (V1),则必须先迁移到版本 2 (V2),然后才能迁移到版本 3 (V3)。请参阅版本 3 中的 Amazon S3 加密客户端迁移(从 V1 到 V2) 适用于 PHP 的 AWS SDK

本主题介绍如何将您的应用程序从亚马逊简单存储服务 (Amazon S3) Simple Service 加密客户端的版本 2 (V2) 迁移到版本 3 (V3),并确保应用程序在整个迁移过程中的可用性。版本 3 引入了 AES GCM 以及密钥承诺和承诺策略,以增强安全性并防止数据密钥被篡改。

迁移概述

此迁移分为两个阶段:

1. 更新现有客户端以读取新格式。首先,将 适用于 PHP 的 AWS SDK 的已更新版本部署到应用程序中。这允许现有的 V2 加密客户端解密新 V3 客户端写入的对象。如果您的应用程序使用多个 SDK AWS SDKs,则必须单独升级每个 SDK。

2. 将加密和解密客户端迁移到 V3。一旦您的所有 V2 加密客户端都能读取新格式,您就可以将现有的加密和解密客户端迁移到各自的 V3 版本。

理解 V3 的概念

Amazon S3 加密客户端第 3 版引入了两项关键安全增强功能:承诺策略和带密钥承诺算法的 AES GCM。了解这些概念对于成功迁移至关重要。

承诺政策

承诺策略控制加密客户端在加密和解密操作期间如何处理密钥承诺。版本 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

带密钥承诺的 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 和 Amazon S3 加密客户端的最新 V2 实现进行解密。V1 客户端无法解密使用此算法加密的对象。

重要

升级要求:在启用加密之前ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY(使用 REQUIRE_ENCRYPT_ALLOW_DECRYPT 或 REQUIRE_ENCRYPT 策略),必须确保所有需要读取加密对象的客户端都已升级到 V3。未能升级所有读取器将导致使用密钥承诺加密的对象解密失败。

更新现有客户端以读取新格式

V3 加密客户端使用旧版本的客户端不支持的加密算法和密钥承诺功能。迁移的第一步是将 V2 解密客户端更新到最新的 SDK 版本。完成此步骤后,您的应用程序的 V2 客户端将能够解密由 V3 加密客户端加密的对象。有关每种安装方法的详细信息,请参阅下文 适用于 PHP 的 AWS SDK。

构建并安装最新的 SDK 版本

要完成此迁移,您必须使用aws/aws-sdk-php包含 V3 加密客户端支持的最新版本的软件包。

从 Composer 安装

对于使用 Composer 安装的项目,请在 Composer 文件中将 SDK 包更新到最新版本的 SDK,然后运行以下命令。

composer update aws/aws-sdk-php

使用 Phar 或 Zip 文件进行安装

使用以下方法之一。请务必将已更新的 SDK 文件放在代码所需位置,该位置由 require 语句确定。

对于使用 Phar 文件来安装的项目,请下载已更新的文件:aws.phar

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

对于使用 Zip 文件来安装的项目,请下载已更新的文件:

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

构建、安装和部署应用程序

更新 SDK 后,重新构建并重新部署您的应用程序,以确保所有组件都使用更新的版本。此步骤对于确保您的 V2 客户端可以读取由 V3 客户端加密的对象至关重要。

按照贵组织的标准部署程序推出更新的应用程序。在继续将加密和解密客户端迁移到 V3 之前,请确保应用程序的所有实例都已更新。

部署后,请验证您的应用程序是否仍然可以解密现有对象,并且在正常操作期间没有出现错误。这可以确认 SDK 更新已成功并且您的应用程序已准备好进入下一阶段的迁移。

将加密和解密客户端迁移到 V3

更新客户端以读取新的加密格式后,您可以将应用程序更新为 V3 加密和解密客户端。以下示例向您展示了如何成功地将代码从 V2 迁移到 V3。

使用 V3 加密客户端

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

  • @KmsEncryptionContext参数仍然是putObject操作所必需的

  • @KmsEncryptionContext参数对于getObject操作来说是可选的,它将验证提供的加密上下文是否与对象中的加密上下文相匹配。

  • @SecurityProfile参数控制可以解密哪些加密版本。设置'V3_AND_LEGACY'为支持在迁移期间读取 V1 和 V2 加密的对象

  • @CommitmentPolicy参数控制此操作的承诺策略。设置'FORBID_ENCRYPT_ALLOW_DECRYPT'为支持在迁移期间读取非承诺加密对象

其他示例

以下示例演示了 V3 中可用的其他配置选项,这些选项可以帮助您管理迁移过程和控制加密行为。

启用旧版 支持

在迁移过程中,您可能需要解密使用 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'以确保最大限度地提高安全性。

配置存储方法

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'存储空间的对象无法从这种额外保护中受益。