在 Amazon S3 中檢查物件完整性 - Amazon Simple Storage Service

在 Amazon S3 中檢查物件完整性

Amazon S3 使用檢查總和值來驗證您上傳或下載的資料完整性。此外,您可以請求為儲存在 Amazon S3 中的任何物件計算另一個檢查總和值。您可以選擇要在上傳、複製或批次複製資料時使用的檢查總和演算法。

當您上傳資料時,Amazon S3 會使用您選擇的演算法在伺服器端計算檢查總和,並使用提供的值進行驗證,再儲存物件並將檢查總和作為物件中繼資料的一部分儲存。無論是單一組件上傳還是分段上傳,此驗證一致適用於各種加密模式、物件大小和儲存類別。不過,當您複製或批次複製資料時,Amazon S3 會計算來源物件的檢查總和,並將其移至目的地物件。

注意

當您執行單一組件上傳或分段上傳時,您可以選擇在請求中包含預先計算的檢查總和,並使用完整物件檢查總和類型。若要對多個物件使用預先計算的值,請使用 AWS CLI 或 AWS SDK。

使用支持的檢查總和演算法

透過 Amazon S3,您可以選擇檢查總和演算法,以在上傳期間驗證您的資料。然後,指定的檢查總和演算法會與您的物件儲存在一起,以便在下載期間用於驗證資料完整性。您可以選擇下列安全雜湊演算法 (SHA) 或循環冗餘檢查 (CRC) 檢查總和演算法來計算檢查總和值:

  • CRC64-NVME (推薦)

  • CRC-32

  • CRC-32C

  • SHA-1

  • SHA-256

此外,您還可以使用 Content-MD5 標頭來提供每個請求的檢查總和。

當您上傳物件時,您可以指定要使用的演算法:

  • 當您使用 AWS Management Console時,請選擇您要使用的檢查總和演算法。您可以選擇指定物件的檢查總和值。Amazon S3 接收物件時,它會使用您指定的演算法計算檢查總和。如果兩個檢查總和值不相符,Amazon S3 會產生錯誤。

  • 當您使用 SDK 時,請注意下列事項:

    • ChecksumAlgorithm 參數設定為您希望 Amazon S3 使用的演算法。如果您已有預先計算的檢查總和,您可以將檢查總和值傳遞至 AWS SDK,SDK 會在請求中包含該值。如果您未傳遞檢查總和值或未指定檢查總和演算法,SDK 會自動為您計算檢查總和值並在請求中包含該值,以提供完整性保護。如果個別檢查總和值不符合檢查總和演算法的設定值,Amazon S3 的請求會失敗並顯示 BadDigest 錯誤。

    • 如果您使用的是升級的 AWS SDK,則 SDK 會為您選擇檢查總和演算法。不過,您可以覆寫此檢查總和演算法。

    • 如果您未指定檢查總和演算法,且 SDK 也不會為您計算檢查總和,則 S3 會自動選擇 CRC-64NVME 檢查總和演算法。

  • 當您使用 REST API 時,請勿使用 x-amz-sdk-checksum-algorithm 參數。反之,請使用演算法特定的標頭之一 (例如 x-amz-checksum-crc32)。

若要將這些檢查總和值套用至已上傳至 Amazon S3 的物件,您可以複製該物件,並指定您想要使用現有的或新的檢查總和演算法。如果您未指定演算法,S3 會使用現有的演算法。如果來源物件沒有指定的檢查總和演算法或檢查總和值,Amazon S3 會使用 CRC64-NVME 演算法來計算目的地物件的檢查總和值。您也可以在使用 S3 Batch Operations 複製物件時指定檢查總和演算法。

重要

如果您搭配檢查總和使用分段上傳以取得複合 (或組件層級) 檢查總和,分段上傳的組件編號必須是連續的。如果您嘗試使用非連續的組件編號完成分段上傳請求,則 Amazon S3 會產生 HTTP 500 Internal Server 錯誤。

完整物件與複合檢查總和類型

在 Amazon S3 中,支援兩種檢查總和類型:

  • 完整物件檢查總和:完整物件檢查總和是根據分段上傳的所有內容來計算,涵蓋從第一個組件第一個位元組到最後一個組件最後一個位元組的所有資料。

    注意

    所有 PUT 請求都需要完整物件檢查總和類型。

  • 複合檢查總和:複合檢查總和是根據分段上傳中每個組件的個別檢查總和來計算。此方法不會根據所有資料內容計算檢查總和,而是彙總組件層級檢查總和 (從第一個組件到最後一個組件),以產生完整物件的單一合併檢查總和。

    注意

    當物件以分段上傳方式上傳時,該物件的實體標籤 (ETag) 不會是整個物件的 MD5 摘要。反之,Amazon S3 會在上傳時計算每個組件的 MD5 摘要。MD5 摘要用於確定最終物件的 ETag。Amazon S3 將 MD5 摘要的位元連接在一起,然後計算這些 MD5 摘要的連接值。在建立 ETag 的最後一個步驟中,Amazon S3 會在結尾加上破折號,後面接著組件總數。

Amazon S3 支援下列完整物件和複合檢查總和演算法類型:

  • CRC-64NVME:僅支援完整物件演算法類型。

  • CRC-32:支援完整物件和複合演算法類型。

  • CRC-32C:支援完整物件和複合演算法類型。

  • SHA-1:支援完整物件和複合演算法類型。

  • SHA-256:支援完整物件和複合演算法類型。

單一組件上傳

以單一組件上傳 (使用 PutObject) 之物件的檢查總和會視為完整物件檢查總和。當您在 Amazon S3 主控台中上傳物件時,您可以選擇希望 S3 使用的檢查總和演算法,也可以選擇提供預先計算的值。然後,Amazon S3 會驗證此檢查總和,再儲存物件及其檢查總和值。您可以在下載物件期間請求檢查總和值時,驗證物件的資料完整性。

分段上傳

當您使用 MultipartUpload API 以多個組件上傳物件時,您可以指定希望 Amazon S3 使用的檢查總和演算法,以及檢查總和類型 (完整物件或複合)。

下表指出分段上傳中每個檢查總和演算法支援的檢查總和演算法類型:

檢查總和演算法 完整物件 複合
CRC-64NVME
CRC-32
CRC-32C
SHA-1
SHA-256

對分段上傳使用完整物件檢查總和

建立或執行分段上傳時,您可以使用完整物件檢查總和來驗證上傳。這表示您可以為 MultipartUpload API 提供檢查總和演算法,從而簡化完整性驗證工具,因為您不再需要追蹤上傳物件的組件界限。您可以提供 CompleteMultipartUpload 請求中整個物件的檢查總和,以及物件大小。

當您在分段上傳期間提供完整物件檢查總和時,AWS SDK 會將檢查總和傳遞至 Amazon S3,而 S3 會在伺服器端驗證物件完整性,並將其與收到的值進行比較。如果值相符,則 Amazon S3 會儲存物件。如果這兩個值不相符,S3 的請求會失敗並顯示 BadDigest 錯誤。物件的檢查總和也會儲存在物件中繼資料內,以供稍後用來驗證物件的資料完整性。

對於完整物件檢查總和,您可以在 S3 中使用 CRC-64NVMECRC-32CRC-32C 檢查總和演算法。分段上傳中的完整物件檢查總和僅適用於 CRC 型檢查總和,因為其可線性化為完整物件檢查總和。此線性化可讓 Amazon S3 平行處理您的請求,以提升效能。特別是,S3 可以從組件層級檢查總和計算整個物件的檢查總和。這種驗證類型不適用於其他演算法 (例如 SHA 和 MD5)。由於 S3 具有預設完整性保護,如果物件在沒有檢查總和的情況下上傳,S3 會自動將建議的完整物件 CRC-64NVME 檢查總和演算法連接至物件。

注意

若要啟動分段上傳,您可以指定檢查總和演算法和完整物件檢查總和類型。指定檢查總和演算法和完整物件檢查總和類型之後,您可以為分段上傳提供完整物件檢查總和值。

對分段上傳使用組件層級檢查總和

當物件上傳至 Amazon S3 時,可作為單一物件上傳,或透過分段上傳程序作為多個組件上傳。您可以選擇分段上傳的檢查總和類型。對於分段上傳組件層級檢查總和 (或複合檢查總和),Amazon S3 會使用指定的檢查總和演算法來計算每個組件的檢查總和。您可以使用 UploadPart 來提供每個組件的檢查總和值。如果您嘗試在 Amazon S3 主控台中上傳的物件設定為使用 CRC-64NVME 檢查總和演算法且超過 16 MB,則會自動將其指定為完整物件檢查總和。

然後,Amazon S3 會使用儲存的組件層級檢查總和值來確認每個組件都已正確上傳。為整個物件提供每個組件的檢查總和時,S3 會使用每個組件的儲存檢查總和值在內部計算完整物件檢查總和,並將其與提供的檢查總和值進行比較。這可將運算成本降到最低,因為 S3 可以使用組件的檢查總和來計算整個物件的檢查總和。如需分段上傳的詳細資訊,請參閱在 Amazon S3 中使用分段上傳來上傳和複製物件對分段上傳使用完整物件檢查總和

物件完全上傳之後,您可以使用最終計算的檢查總和來驗證物件的資料完整性。

分段上傳組件時,請注意下列事項:

  • 若要擷取物件的相關資訊 (包括構成整個物件的組件數目),您可以使用 GetObjectAttributes 操作。透過額外的檢查總和,您也可以復原每個組件的資訊 (包括組件的檢查總和值)。

  • 對於已完成的上傳,您可以使用 GetObjectHeadObject 操作,並指定組件編號或符合單一組件的位元組範圍,來取得個別組件的檢查總和。如果您想要在分段上傳仍在進行時,擷取個別組件的檢查總和值,則可以使用 ListParts

  • 由於 Amazon S3 計算分段上傳物件的檢查總和的方式,物件的檢查總和值可能會因為複製而變更。如果您使用 SDK 或 REST API,並且呼叫 CopyObject,則 Amazon S3 可複製不超過 CopyObject API 操作大小限制的任何物件。無論物件是由單個請求上傳還是作為分段上傳的一部分,Amazon S3 都會將此複製作為單獨操作進行。使用複製命令,物件的檢查總和是完整物件的直接檢查總和。如果物件最初是使用分段上傳方式進行上傳,即使資料沒有變更,檢查總和值也會變更。

  • 超過 CopyObject API 操作大小上限的物件必須使用分段複製命令

  • 當您使用 AWS Management Console 執行部分操作時,如果物件大小超過 16 MB,則 Amazon S3 將使用分段上傳。

檢查總和操作

上傳物件之後,您可以取得檢查總和值,並將其與相同演算法類型之預先計算或先前儲存的檢查總和值進行比較。下列範例顯示您可以使用哪些檢查總和操作或方法來驗證資料完整性。

若要進一步了解如何使用主控台,以及如何指定上傳物件時要使用的檢查總和演算法,請參閱 上傳物件教學課程:使用其他檢查總和來檢查 Amazon S3 中資料的完整性

下列範例示範如何使用 AWS SDK 透過分段上傳上傳大型檔案、下載大型檔案以及驗證分段上傳檔案,所有檔案都會使用 SHA-256 進行驗證。

Java
範例:使用 SHA-256 上傳、下載和驗證大型檔案

如需建立和測試可行範例的說明,請參閱《AWS SDK for Java開發人員指南》中的入門

import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.core.ResponseInputStream; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest; import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm; import software.amazon.awssdk.services.s3.model.ChecksumMode; import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest; import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse; import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload; import software.amazon.awssdk.services.s3.model.CompletedPart; import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest; import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse; import software.amazon.awssdk.services.s3.model.GetObjectAttributesRequest; import software.amazon.awssdk.services.s3.model.GetObjectAttributesResponse; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.model.GetObjectTaggingRequest; import software.amazon.awssdk.services.s3.model.ObjectAttributes; import software.amazon.awssdk.services.s3.model.PutObjectTaggingRequest; import software.amazon.awssdk.services.s3.model.Tag; import software.amazon.awssdk.services.s3.model.Tagging; import software.amazon.awssdk.services.s3.model.UploadPartRequest; import software.amazon.awssdk.services.s3.model.UploadPartResponse; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Base64; import java.util.List; public class LargeObjectValidation { private static String FILE_NAME = "sample.file"; private static String BUCKET = "sample-bucket"; //Optional, if you want a method of storing the full multipart object checksum in S3. private static String CHECKSUM_TAG_KEYNAME = "fullObjectChecksum"; //If you have existing full-object checksums that you need to validate against, you can do the full object validation on a sequential upload. private static String SHA256_FILE_BYTES = "htCM5g7ZNdoSw8bN/mkgiAhXt5MFoVowVg+LE9aIQmI="; //Example Chunk Size - this must be greater than or equal to 5MB. private static int CHUNK_SIZE = 5 * 1024 * 1024; public static void main(String[] args) { S3Client s3Client = S3Client.builder() .region(Region.US_EAST_1) .credentialsProvider(new AwsCredentialsProvider() { @Override public AwsCredentials resolveCredentials() { return new AwsCredentials() { @Override public String accessKeyId() { return Constants.ACCESS_KEY; } @Override public String secretAccessKey() { return Constants.SECRET; } }; } }) .build(); uploadLargeFileBracketedByChecksum(s3Client); downloadLargeFileBracketedByChecksum(s3Client); validateExistingFileAgainstS3Checksum(s3Client); } public static void uploadLargeFileBracketedByChecksum(S3Client s3Client) { System.out.println("Starting uploading file validation"); File file = new File(FILE_NAME); try (InputStream in = new FileInputStream(file)) { MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder() .bucket(BUCKET) .key(FILE_NAME) .checksumAlgorithm(ChecksumAlgorithm.SHA256) .build(); CreateMultipartUploadResponse createdUpload = s3Client.createMultipartUpload(createMultipartUploadRequest); List<CompletedPart> completedParts = new ArrayList<CompletedPart>(); int partNumber = 1; byte[] buffer = new byte[CHUNK_SIZE]; int read = in.read(buffer); while (read != -1) { UploadPartRequest uploadPartRequest = UploadPartRequest.builder() .partNumber(partNumber).uploadId(createdUpload.uploadId()).key(FILE_NAME).bucket(BUCKET).checksumAlgorithm(ChecksumAlgorithm.SHA256).build(); UploadPartResponse uploadedPart = s3Client.uploadPart(uploadPartRequest, RequestBody.fromByteBuffer(ByteBuffer.wrap(buffer, 0, read))); CompletedPart part = CompletedPart.builder().partNumber(partNumber).checksumSHA256(uploadedPart.checksumSHA256()).eTag(uploadedPart.eTag()).build(); completedParts.add(part); sha256.update(buffer, 0, read); read = in.read(buffer); partNumber++; } String fullObjectChecksum = Base64.getEncoder().encodeToString(sha256.digest()); if (!fullObjectChecksum.equals(SHA256_FILE_BYTES)) { //Because the SHA256 is uploaded after the part is uploaded; the upload is bracketed and the full object can be fully validated. s3Client.abortMultipartUpload(AbortMultipartUploadRequest.builder().bucket(BUCKET).key(FILE_NAME).uploadId(createdUpload.uploadId()).build()); throw new IOException("Byte mismatch between stored checksum and upload, do not proceed with upload and cleanup"); } CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder().parts(completedParts).build(); CompleteMultipartUploadResponse completedUploadResponse = s3Client.completeMultipartUpload( CompleteMultipartUploadRequest.builder().bucket(BUCKET).key(FILE_NAME).uploadId(createdUpload.uploadId()).multipartUpload(completedMultipartUpload).build()); Tag checksumTag = Tag.builder().key(CHECKSUM_TAG_KEYNAME).value(fullObjectChecksum).build(); //Optionally, if you need the full object checksum stored with the file; you could add it as a tag after completion. s3Client.putObjectTagging(PutObjectTaggingRequest.builder().bucket(BUCKET).key(FILE_NAME).tagging(Tagging.builder().tagSet(checksumTag).build()).build()); } catch (IOException | NoSuchAlgorithmException e) { e.printStackTrace(); } GetObjectAttributesResponse objectAttributes = s3Client.getObjectAttributes(GetObjectAttributesRequest.builder().bucket(BUCKET).key(FILE_NAME) .objectAttributes(ObjectAttributes.OBJECT_PARTS, ObjectAttributes.CHECKSUM).build()); System.out.println(objectAttributes.objectParts().parts()); System.out.println(objectAttributes.checksum().checksumSHA256()); } public static void downloadLargeFileBracketedByChecksum(S3Client s3Client) { System.out.println("Starting downloading file validation"); File file = new File("DOWNLOADED_" + FILE_NAME); try (OutputStream out = new FileOutputStream(file)) { GetObjectAttributesResponse objectAttributes = s3Client.getObjectAttributes(GetObjectAttributesRequest.builder().bucket(BUCKET).key(FILE_NAME) .objectAttributes(ObjectAttributes.OBJECT_PARTS, ObjectAttributes.CHECKSUM).build()); //Optionally if you need the full object checksum, you can grab a tag you added on the upload List<Tag> objectTags = s3Client.getObjectTagging(GetObjectTaggingRequest.builder().bucket(BUCKET).key(FILE_NAME).build()).tagSet(); String fullObjectChecksum = null; for (Tag objectTag : objectTags) { if (objectTag.key().equals(CHECKSUM_TAG_KEYNAME)) { fullObjectChecksum = objectTag.value(); break; } } MessageDigest sha256FullObject = MessageDigest.getInstance("SHA-256"); MessageDigest sha256ChecksumOfChecksums = MessageDigest.getInstance("SHA-256"); //If you retrieve the object in parts, and set the ChecksumMode to enabled, the SDK will automatically validate the part checksum for (int partNumber = 1; partNumber <= objectAttributes.objectParts().totalPartsCount(); partNumber++) { MessageDigest sha256Part = MessageDigest.getInstance("SHA-256"); ResponseInputStream<GetObjectResponse> response = s3Client.getObject(GetObjectRequest.builder().bucket(BUCKET).key(FILE_NAME).partNumber(partNumber).checksumMode(ChecksumMode.ENABLED).build()); GetObjectResponse getObjectResponse = response.response(); byte[] buffer = new byte[CHUNK_SIZE]; int read = response.read(buffer); while (read != -1) { out.write(buffer, 0, read); sha256FullObject.update(buffer, 0, read); sha256Part.update(buffer, 0, read); read = response.read(buffer); } byte[] sha256PartBytes = sha256Part.digest(); sha256ChecksumOfChecksums.update(sha256PartBytes); //Optionally, you can do an additional manual validation again the part checksum if needed in addition to the SDK check String base64PartChecksum = Base64.getEncoder().encodeToString(sha256PartBytes); String base64PartChecksumFromObjectAttributes = objectAttributes.objectParts().parts().get(partNumber - 1).checksumSHA256(); if (!base64PartChecksum.equals(getObjectResponse.checksumSHA256()) || !base64PartChecksum.equals(base64PartChecksumFromObjectAttributes)) { throw new IOException("Part checksum didn't match for the part"); } System.out.println(partNumber + " " + base64PartChecksum); } //Before finalizing, do the final checksum validation. String base64FullObject = Base64.getEncoder().encodeToString(sha256FullObject.digest()); String base64ChecksumOfChecksums = Base64.getEncoder().encodeToString(sha256ChecksumOfChecksums.digest()); if (fullObjectChecksum != null && !fullObjectChecksum.equals(base64FullObject)) { throw new IOException("Failed checksum validation for full object"); } System.out.println(fullObjectChecksum); String base64ChecksumOfChecksumFromAttributes = objectAttributes.checksum().checksumSHA256(); if (base64ChecksumOfChecksumFromAttributes != null && !base64ChecksumOfChecksums.equals(base64ChecksumOfChecksumFromAttributes)) { throw new IOException("Failed checksum validation for full object checksum of checksums"); } System.out.println(base64ChecksumOfChecksumFromAttributes); out.flush(); } catch (IOException | NoSuchAlgorithmException e) { //Cleanup bad file file.delete(); e.printStackTrace(); } } public static void validateExistingFileAgainstS3Checksum(S3Client s3Client) { System.out.println("Starting existing file validation"); File file = new File("DOWNLOADED_" + FILE_NAME); GetObjectAttributesResponse objectAttributes = s3Client.getObjectAttributes(GetObjectAttributesRequest.builder().bucket(BUCKET).key(FILE_NAME) .objectAttributes(ObjectAttributes.OBJECT_PARTS, ObjectAttributes.CHECKSUM).build()); try (InputStream in = new FileInputStream(file)) { MessageDigest sha256ChecksumOfChecksums = MessageDigest.getInstance("SHA-256"); MessageDigest sha256Part = MessageDigest.getInstance("SHA-256"); byte[] buffer = new byte[CHUNK_SIZE]; int currentPart = 0; int partBreak = objectAttributes.objectParts().parts().get(currentPart).size(); int totalRead = 0; int read = in.read(buffer); while (read != -1) { totalRead += read; if (totalRead >= partBreak) { int difference = totalRead - partBreak; byte[] partChecksum; if (totalRead != partBreak) { sha256Part.update(buffer, 0, read - difference); partChecksum = sha256Part.digest(); sha256ChecksumOfChecksums.update(partChecksum); sha256Part.reset(); sha256Part.update(buffer, read - difference, difference); } else { sha256Part.update(buffer, 0, read); partChecksum = sha256Part.digest(); sha256ChecksumOfChecksums.update(partChecksum); sha256Part.reset(); } String base64PartChecksum = Base64.getEncoder().encodeToString(partChecksum); if (!base64PartChecksum.equals(objectAttributes.objectParts().parts().get(currentPart).checksumSHA256())) { throw new IOException("Part checksum didn't match S3"); } currentPart++; System.out.println(currentPart + " " + base64PartChecksum); if (currentPart < objectAttributes.objectParts().totalPartsCount()) { partBreak += objectAttributes.objectParts().parts().get(currentPart - 1).size(); } } else { sha256Part.update(buffer, 0, read); } read = in.read(buffer); } if (currentPart != objectAttributes.objectParts().totalPartsCount()) { currentPart++; byte[] partChecksum = sha256Part.digest(); sha256ChecksumOfChecksums.update(partChecksum); String base64PartChecksum = Base64.getEncoder().encodeToString(partChecksum); System.out.println(currentPart + " " + base64PartChecksum); } String base64CalculatedChecksumOfChecksums = Base64.getEncoder().encodeToString(sha256ChecksumOfChecksums.digest()); System.out.println(base64CalculatedChecksumOfChecksums); System.out.println(objectAttributes.checksum().checksumSHA256()); if (!base64CalculatedChecksumOfChecksums.equals(objectAttributes.checksum().checksumSHA256())) { throw new IOException("Full object checksum of checksums don't match S3"); } } catch (IOException | NoSuchAlgorithmException e) { e.printStackTrace(); } } }

您可以發送 REST 請求以上傳具有檢查總和值的物件,以使用 PutObject 驗證資料的完整性。您也可以使用適用於 GetObjectHeadObject 物件擷取檢查總和的值。

您可以傳送 PUT 請求,以便在單一操作中上傳多達 5 GB 的物件。如需詳細資訊,請參閱《AWS CLI 命令參考》中的 PutObject。您也可以使用 get-objecthead-object 以擷取已上傳物件的檢查總和以驗證資料的完整性。

如需相關資訊,請參閱《AWS Command Line Interface 使用者指南》中的 Amazon S3 CLI 常見問答集

上傳物件時使用 Content-MD5

上傳後驗證物件完整性的另一種方法,是在上傳物件時提供物件的 MD5 摘要。如果要計算物件的 MD5 摘要,您可以使用 Content-MD5 標頭搭配 PUT 命令提供摘要。

上傳物件後,Amazon S3 會計算物件的 MD5 摘要,並將其與您提供的值進行比較。僅當兩個摘要匹配時,請求才會成功。

MD5 摘要不是強制需求,但您可以將其用於上傳過程以驗證物件的完整性。

使用 Content-MD5 和 ETag 驗證上傳的物件

物件的實體標籤 (ETag) 表示物件的特定版本。請記住,ETag 只會反映物件內容的變更,不會反映其中繼資料的變更。如果僅變更物件的中繼資料,則 ETag 將保持不變。

根據物件的不同,物件的 ETag 可能是物件資料的 MD5 摘要:

  • 如果物件是由 PutObjectPostObject,或 CopyObject 操作所建立,或是通過 AWS Management Console,並且該物件也是採用 Amazon S3 受管金鑰 (SSE-S3) 的伺服器端加密或加密,則物件的 ETag 是該物件資料的 MD5 摘要。

  • 如果一個對象是由 PutObjectPostObject,或 CopyObject 操作所建立,或是通過 AWS Management Console,並且該物件的加密方式是使用客戶提供之金鑰 (SSE-C) 的伺服器端加密,或使用 AWS Key Management Service (AWS KMS) 金鑰 (SSE-KMS) 加密,則該物件的 ETag 不會是物件資料的 MD5 摘要。

  • 如果物件是由分段上傳程序或 UploadPartCopy 操作所建立,則無論加密方法為何,物件的 ETag 都不會是 MD5 摘要。如果物件大於 16 MB,則會以分段上傳的方式 AWS Management Console 上傳或複製該物件,因此 ETag 不會是 MD5 摘要。

對於物件 ETag 是否為 Content-MD5 摘要,您可以將物件的 ETag 值與計算值或先前儲存的 Content-MD5 摘要進行比較。

使用追蹤檢查總和

將物件上傳到 Amazon S3 時,您可以為物件提供預先計算的檢查總和,也可以使用 AWS SDK 為您自動建立追蹤檢查總和。如果您決定使用追蹤檢查總和,則 Amazon S3 會使用您指定的演算法自動產生檢查總和,以在物件上傳期間驗證物件的完整性。

若要在使用 AWS SDK 時建立追蹤檢查總和,請填充 ChecksumAlgorithm 參數與您偏好的演算法結合。SDK 使用該演算法來計算物件 (或對象物件) 的檢查總和,並自動將其附加到上傳請求的最後。此行為可節省您的時間,因為 Amazon S3 一次同時執行驗證和上傳您的資料。

重要

如果您使用的是 S3 物件 Lambda,則對 S3 物件 Lambda 的所有請求都使用 s3-object-lambda 而不是 s3。此行為會影響追蹤檢查總和值的簽名。如需 S3 Object Lambda 的詳細資訊,請參閱 使用 S3 Object Lambda 轉換物件