Verifica dell’integrità degli oggetti per caricamenti dei dati in Amazon S3 - Amazon Simple Storage Service

Verifica dell’integrità degli oggetti per caricamenti dei dati in Amazon S3

Amazon S3 utilizza valori di checksum per verificare l’integrità dei dati durante le operazioni di caricamento e download. Quando carichi i dati, AWS SDK e la Console di gestione AWS utilizzano l’algoritmo di checksum scelto per calcolare un valore di checksum prima della trasmissione dei dati. S3 calcola quindi in modo indipendente un checksum dei dati e lo convalida rispetto al valore di checksum fornito. Gli oggetti vengono accettati solo dopo aver confermato che l’integrità dei dati è stata mantenuta durante il transito. S3 archivia il valore di checksum come metadati dell’oggetto e l’oggetto stesso.

Per verificare l’integrità dell’oggetto, è possibile richiedere il valore di checksum durante i download. Questa convalida funziona in modo coerente in tutte le modalità di crittografia, dimensioni degli oggetti, classi di archiviazione e in tutti i caricamenti sia di singole parti sia in più parti. Per modificare l’algoritmo di checksum per un caricamento, puoi copiare un singolo oggetto o utilizzare la copia in batch per più oggetti.

Per i caricamenti di singole parti, puoi fornire valori di checksum come intestazioni. È possibile fornire un valore precalcolato o lasciare che AWS SDK ne calcoli uno durante il caricamento. Se il valore di checksum calcolato da S3 corrisponde al valore fornito, la richiesta viene accettata. Se i valori non corrispondono, la richiesta viene rifiutata.

Per i caricamenti in più parti, gli AWS SDK possono creare automaticamente checksum finali per i caricamenti suddivisi in blocchi. Quando usi un checksum finale, Amazon S3 genera valori di checksum per ogni parte utilizzando l’algoritmo specificato e aggiunge il valore di checksum alla fine della richiesta di caricamento in blocchi. S3 esegue la verifica e il caricamento in un unico passaggio, migliorando l’efficienza. Per ulteriori informazioni, consulta le Utilizzo dei checksum finali.

Utilizzo di algoritmi di checksum supportati

Con Amazon S3, è possibile scegliere un algoritmo di checksum per convalidare i valori di checksum durante i caricamenti. L'algoritmo di checksum specificato viene quindi memorizzato con l'oggetto e può essere usato per convalidare l'integrità dei dati durante i download. È possibile scegliere uno dei seguenti algoritmi di checksum Secure Hash Algorithms (SHA) o Cyclic Redundancy Check (CRC) per calcolare il valore di checksum:

  • CRC-64/NVME (CRC64NVME)

  • CRC-32 (CRC32)

  • CRC-32C (CRC32C)

  • SHA-1 (SHA1)

  • SHA-256 (SHA256)

  • MD5 (MD5)

    Nota

    L’intestazione content-MD5 è disponibile solo utilizzando l’ETag S3 per gli oggetti caricati in un caricamento di una singola parte (operazione PUT) che utilizza la crittografia SSE-S3.

Inoltre, è possibile fornire un checksum con ogni richiesta utilizzando l'intestazione Content-MD5.

Quando si carica un oggetto, si specifica l'algoritmo che si desidera utilizzare:

  • Quando usi Console di gestione AWS, scegli l'algoritmo di checksum da utilizzare. È possibile specificare facoltativamente il valore di checksum dell'oggetto. Quando Amazon S3 riceve l'oggetto, calcola il checksum utilizzando l'algoritmo specificato. Se i due valori di checksum non corrispondono, Amazon S3 genera un errore.

  • Quando si utilizza un SDK, tieni presente quanto segue:

    • Imposta il parametro ChecksumAlgorithm sull'algoritmo da utilizzare per Amazon S3. Se si dispone già di un checksum precalcolato, si trasmette il valore del checksum all'SDK AWS, che lo include nella richiesta. Se non si trasmette un valore di checksum o non si specifica un algoritmo di checksum, l'SDK calcola automaticamente un valore di checksum per l'utente e lo include nella richiesta per garantire la protezione dell'integrità. Se il valore del checksum individuale non corrisponde al valore impostato dell'algoritmo di checksum, Amazon S3 respinge la richiesta con un errore BadDigest.

    • Se si utilizza un SDK aggiornato AWS, l'SDK sceglie un algoritmo di checksum per l'utente. Tuttavia, è possibile ignorare questo algoritmo di checksum.

    • Se non si specifica un algoritmo di checksum e SDK non calcola un checksum, S3 sceglie automaticamente l’algoritmo di checksum CRC-64/NVME (CRC64NVME).

  • Quando utilizzi la REST API, non utilizzare il parametro x-amz-sdk-checksum-algorithm. Utilizza invece una delle intestazioni specifiche dell'algoritmo (ad esempio, x-amz-checksum-crc32).

Per applicare uno di questi valori di checksum a oggetti già caricati su Amazon S3, è possibile copiare l'oggetto e specificare se si desidera utilizzare l'algoritmo di checksum esistente o uno nuovo. Se non si specifica un algoritmo, S3 utilizza l'algoritmo esistente. Se l’oggetto di origine non ha un algoritmo di checksum o un valore di checksum specificato, Amazon S3 utilizza l’algoritmo CRC-64/NVME per calcolare il valore di checksum dell’oggetto di destinazione. È inoltre possibile specificare un algoritmo di checksum quando si copiano gli oggetti utilizzando le Operazioni in batch S3.

Importante

Se si utilizza un caricamento in più parti con Checksum per checksum compositi (o a livello di parte), i numeri di parte del caricamento in più parti devono essere consecutivi e iniziare con 1. Se si tenta di completare una richiesta di caricamento multiparte con numeri di parte non consecutivi, Amazon S3 genera un errore HTTP 500 Internal Server.

Tipi di checksum di oggetti completi e compositi

In Amazon S3, esistono due tipi di checksum supportati:

  • Checksum di oggetti completi: un checksum dell'oggetto completo viene calcolato sulla base di tutto il contenuto di un caricamento multiparte, coprendo tutti i dati dal primo byte della prima parte all'ultimo byte dell'ultima parte. Tieni presente che se utilizzi la Console di gestione AWS per caricare oggetti di dimensioni inferiori a 16 MB, è supportato solo il tipo di checksum dell’oggetto completo.

    Nota

    Tutte le richieste PUT richiedono un tipo di checksum dell'oggetto completo. È necessario specificare il tipo di checksum dell’oggetto completo se si carica l’oggetto tramite una richiesta PUT.

  • Checksum compositi: un checksum composito viene calcolato in base ai singoli checksum di ciascuna parte di un caricamento multiparte. Invece di calcolare un checksum basato su tutto il contenuto dei dati, questo approccio aggrega i checksum a livello di parte (dalla prima all'ultima parte) per produrre un singolo checksum combinato per l'oggetto completo. Se si utilizza un caricamento in più parti per caricare l’oggetto, è necessario specificare il tipo di checksum composito.

    Nota

    Quando un oggetto viene caricato come caricamento multiparte, il tag entità (ETag) per l'oggetto non è un digest MD5 dell'intero oggetto. Invece, Amazon S3 calcola il digest MD5 di ogni singola parte mentre viene caricata. I digest MD5 vengono utilizzati per determinare l'ETag dell'oggetto finale. Amazon S3 concatena i byte per i digest MD5 e quindi calcola il digest MD5 di questi valori concatenati. Durante la fase finale di creazione dell'ETag, Amazon S3 aggiunge un trattino con il numero totale di parti alla fine.

Amazon S3 supporta i seguenti tipi di algoritmi di checksum completi e compositi:

  • CRC-64/NVME (CRC64NVME): supporta solo il tipo di checksum dell’oggetto completo.

  • CRC-32 (CRC32): supporta il tipo di checksum dell’oggetto completo e composito.

  • CRC-32C (CRC32C): supporta il tipo di checksum dell’oggetto completo e composito.

  • SHA-1 (SHA1): supporta il tipo di checksum dell’oggetto completo e composito.

  • SHA-256 (SHA256): supporta il tipo di checksum dell’oggetto completo e composito.

  • MD5 (MD5): supporta il tipo di checksum dell’oggetto completo e composito.

Caricamenti di una singola parte

I checksum degli oggetti caricati in una singola parte (usando il metodo PutObject) sono trattati come checksum completi dell'oggetto. Quando si carica un oggetto nella console di Amazon S3, è possibile scegliere l'algoritmo di checksum che si desidera che S3 utilizzi e anche (facoltativamente) fornire un valore precompilato. Amazon S3 convalida quindi il valore di checksum precalcolato prima di archiviare l’oggetto e il relativo valore di checksum. È possibile verificare l'integrità dei dati di un oggetto quando si richiede il valore di checksum durante il download degli oggetti.

Caricamenti in più parti

Quando si carica l'oggetto in più parti utilizzando l'API MultipartUpload è possibile specificare l'algoritmo di checksum che si desidera utilizzare su Amazon S3 e il tipo di checksum (oggetto completo o composito).

La tabella seguente indica quale tipo di algoritmo di checksum è supportato per ogni algoritmo di checksum in un caricamento multiparte:

Algoritmo di checksum Oggetto completo Composita
CRC-64/NVME (CRC64NVME) No
CRC-32 (CRC32)
CRC-32C (CRC32C)
SHA-1 (SHA1) No
SHA-256 (SHA256) No

Utilizzo di checksum completi degli oggetti per il caricamento multiparte

Quando si crea o si esegue un caricamento multiparte, è possibile utilizzare checksum completi degli oggetti per la convalida del caricamento. Ciò significa che è possibile fornire l'algoritmo di checksum per l'API MultipartUpload semplificando gli strumenti di validazione dell'integrità, perché non è più necessario tracciare vincoli di parti per oggetti caricati. È possibile fornire il checksum dell'intero oggetto nella richiesta CompleteMultipartUpload insieme alla dimensione dell'oggetto.

Quando si fornisce un checksum completo dell'oggetto durante un caricamento multiparte, l'SDK AWS trasmette il checksum ad Amazon S3 e S3 convalida l'integrità dell'oggetto lato server, confrontandolo con il valore ricevuto. Quindi, Amazon S3 memorizza l'oggetto se i valori corrispondono. Se i due valori non coincidono, S3 respinge la richiesta con un errore BadDigest. Il checksum dell'oggetto viene memorizzato anche nei metadati dell'oggetto, che verranno utilizzati in seguito per convalidare l'integrità dei dati di un oggetto.

Per i checksum dell’oggetto completo, è possibile utilizzare gli algoritmi di checksum CRC-64/NVME (CRC64NVME), CRC-32C (CRC32) o CRC-32C (CRC32C) in S3. I checksum completi degli oggetti nei caricamenti multiparte sono disponibili solo per i checksum basati su CRC perché possono linearizzarsi in un checksum completo dell'oggetto. Questa linearizzazione consente ad Amazon S3 di parallelizzare le richieste per migliorare le prestazioni. In particolare, S3 può calcolare il checksum dell'intero oggetto a partire dai checksum a livello di parte. Questo tipo di convalida non è disponibile per altri algoritmi, come SHA e MD5. Poiché S3 dispone di protezioni predefinite per l’integrità, se l’oggetto viene caricato senza checksum, S3 collega automaticamente all’oggetto l’algoritmo di checksum CRC-64/NVME dell’oggetto completo raccomandato (CRC64NVME).

Nota

Per avviare il caricamento multiparte, è possibile specificare l'algoritmo di checksum e il tipo di checksum dell'oggetto completo. Dopo aver specificato l'algoritmo di checksum e il tipo di checksum dell'oggetto completo, è possibile fornire il valore di checksum dell'oggetto completo per il caricamento multiparte.

Utilizzo di checksum a livello di parte per il caricamento multiparte

Quando gli oggetti vengono caricati su Amazon S3, possono essere caricati come un singolo oggetto o in parti con il processo di caricamento multiparte. È possibile scegliere un tipo di checksum per il caricamento multiparte. Per i checksum a livello di parte di caricamento multiparte (o checksum compositi), Amazon S3 calcola il checksum per ogni singola parte utilizzando l'algoritmo di checksum specificato. È possibile utilizzare UploadPart per fornire i valori di checksum per ogni parte. Se l’oggetto che si tenta di caricare nella console Amazon S3 è impostato per l’utilizzo dell’algoritmo di checksum CRC-64/NVME (CRC64NVME) e supera i 16 MB, viene automaticamente designato come checksum dell’oggetto completo.

Amazon S3 utilizza quindi i valori di checksum memorizzati a livello di parte per confermare che ogni parte è stata caricata correttamente. Quando viene fornito il checksum di ogni parte (per l'intero oggetto), S3 utilizza i valori di checksum memorizzati di ogni parte per calcolare internamente il checksum dell'intero oggetto, confrontandolo con il valore di checksum fornito. Questo riduce al minimo i costi di calcolo, poiché S3 può calcolare un checksum dell'intero oggetto utilizzando il checksum delle parti. Per ulteriori informazioni sui caricamenti multiparte, consulta Caricamento e copia di oggetti utilizzando il caricamento multiparte in Amazon S3 e Utilizzo di checksum completi degli oggetti per il caricamento multiparte.

Quando l'oggetto è stato completamente caricato, è possibile utilizzare il checksum finale calcolato per verificare l'integrità dei dati dell'oggetto.

Quando si carica una parte del caricamento multiparte, tieni presente quanto segue:

  • Per recuperare informazioni sull'oggetto, compreso il numero di parti che compongono l'intero oggetto, si può usare l'operazione GetObjectAttributes. Con i checksum aggiuntivi, è possibile recuperare anche le informazioni per ogni singolo componente, che includono il valore del checksum del componente.

  • Per i caricamenti completati, è possibile ottenere la somma di controllo di una singola parte utilizzando i tasti GetObject o HeadObject e specificando un numero di parte o un intervallo di byte che corrisponde a una singola parte. Se si desidera recuperare i valori di checksum per le singole parti dei caricamenti multiparte che sono ancora in corso, si può usare ListParts.

  • A causa del modo in cui Amazon S3 calcola il checksum per gli oggetti in più parti, il valore del checksum dell'oggetto potrebbe cambiare se lo si copia. Se si utilizza un SDK o la REST API e si chiama CopyObject, Amazon S3 copia qualsiasi oggetto fino alle limitazioni di dimensione dell'operazione dell'API CopyObject. Amazon S3 esegue questa copia come un'unica operazione, indipendentemente dal fatto che l'oggetto sia stato caricato in una singola richiesta o come parte di un caricamento in più parti. Con il comando copy, il checksum dell'oggetto è un checksum diretto dell'oggetto completo. Se l'oggetto è stato originariamente caricato con un caricamento multiparte, il valore del checksum cambia anche se i dati non cambiano.

  • Gli oggetti di dimensioni superiori alle limitazioni di dimensione dell'operazione API CopyObject devono utilizzare comandi di copia di caricamento multiparte.

  • Quando si eseguono le operazioni utilizzando la Console di gestione AWS, Amazon S3 utilizza un caricamento in più parti se l'oggetto ha dimensioni superiori a 16 MB.

Metodi di checksum

Dopo aver caricato gli oggetti, è possibile ottenere il valore di checksum e confrontarlo con un valore di checksum precalcolato o precedentemente archiviato dello stesso tipo di algoritmo di checksum. Gli esempi seguenti mostrano quali metodi di calcolo del checksum si possono utilizzare per verificare l’integrità dei dati.

Per ulteriori informazioni sull'utilizzo della console e sulla specifica degli algoritmi di checksum da utilizzare durante il caricamento degli oggetti, consultare Caricamento degli oggetti e Tutorial: Verifica dell'integrità dei dati in Amazon S3 con checksum aggiuntivi.

L'esempio seguente mostra come sia possibile utilizzare gli SDK AWS per caricare un file di grandi dimensioni con caricamento multiparte, scaricare un file di grandi dimensioni e convalidare un file di caricamento multiparte, il tutto utilizzando SHA-256 per la convalida dei file.

Java
Esempio: caricamento, download e verifica di un file di grandi dimensioni con SHA-256

Per istruzioni su come creare e testare un campione funzionante, consulta Nozioni di base nella Guida per gli sviluppatori di AWS SDK per 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(); } } }

Puoi inviare richieste REST per caricare un oggetto con un valore di checksum per verificare l'integrità dei dati con PutObject. È inoltre possibile recuperare il valore di checksum per gli oggetti utilizzando GetObject o HeadObject.

È possibile inviare una richiesta PUT per caricare un oggetto di un massimo di 5 GB in una singola operazione. Per ulteriori informazioni, consulta PutObject nella documentazione di riferimento dei comandi della AWS CLI. Puoi utilizzare anche get-object e head-object per recuperare il checksum di un oggetto già caricato per verificare l'integrità dei dati.

Per informazioni, consulta le Domande frequenti sulla CLI di Amazon S3 nella Guida all'utente AWS Command Line Interface.

Utilizzo di Content-MD5 durante il caricamento di oggetti

Un altro modo per verificare l'integrità dell'oggetto dopo il caricamento consiste nel fornire un digest MD5 dell'oggetto durante il caricamento. Se calcoli il digest MD5 dell'oggetto, puoi fornire il digest con il comando PUTutilizzando l'intestazione Content-MD5.

Dopo aver caricato l'oggetto, Amazon S3 calcola il digest MD5 dell'oggetto e lo confronta con il valore fornito. La richiesta ha esito positivo solo se i due digest corrispondono.

Non è obbligatorio fornire un digest MD5, ma è possibile utilizzarlo per verificare l'integrità dell'oggetto come parte del processo di caricamento.

Utilizzo di Content-MD5 e di ETag per verificare gli oggetti caricati

Il tag di entità (ETag) di un oggetto rappresenta una versione specifica di tale oggetto. Tieni presente che l'ETag riflette solo le modifiche al contenuto di un oggetto, non le modifiche ai suoi metadati. Se cambiano solo i metadati di un oggetto, l'ETag rimane invariato.

In base all'oggetto, l'ETag dell'oggetto potrebbe essere un digest MD5 dei dati dell'oggetto:

  • Se un oggetto viene creato dall'operazione PutObject, PostObject o CopyObject oppure attraverso la Console di gestione AWS e l'oggetto è anche in testo normale o crittografato tramite la crittografia lato server con chiavi gestite da Amazon S3 (SSE-S3), l'oggetto ha un ETag che è un digest MD5 dei dati dell'oggetto.

  • Se un oggetto viene creato dall'operazione PutObject, PostObject o CopyObject oppure attraverso la Console di gestione AWS e l'oggetto è crittografato tramite la crittografia lato server con chiavi fornite dal cliente (SSE-C) o la crittografia lato server con chiavi AWS Key Management Service (AWS KMS) (SSE-KMS), l'oggetto ha un ETag che non è un digest MD5 dei dati dell'oggetto.

  • Se un oggetto viene creato dal processo di caricamento multiparte o dall'operazione UploadPartCopy, l'ETag dell'oggetto non è un digest MD5, indipendentemente dal metodo di crittografia. Se un oggetto è più grande di 16 MB, la Console di gestione AWS carica o copia l'oggetto come caricamento in più parti e quindi l'ETag non è un digest MD5.

Per gli oggetti in cui l'ETag è il digest Content-MD5 dell'oggetto, puoi confrontare il valore ETag dell'oggetto con un digest Content-MD5 calcolato o precedentemente archiviato.

Utilizzo dei checksum finali

Quando si caricano oggetti di grandi dimensioni in Amazon S3, puoi fornire un checksum precalcolato per l’oggetto o utilizzare AWS SDK per creare automaticamente i checksum finali per i caricamenti in blocchi. Se utilizzi un checksum finale, Amazon S3 genera automaticamente il valore di checksum utilizzando l’algoritmo specificato per convalidare l’integrità dell’oggetto durante il caricamento in blocchi di un oggetto.

Per creare un checksum finale quando si utilizza un SDK AWS, compila il parametro ChecksumAlgorithmcon l'algoritmo preferito. SDK utilizza l’algoritmo per calcolare il valore di checksum dell’oggetto (o delle parti dell’oggetto) e lo aggiunge automaticamente alla fine della richiesta di caricamento in blocchi. Questo comportamento ti consente di risparmiare tempo perché Amazon S3 esegue sia la verifica che il caricamento dei tuoi dati in un unico passaggio.

Importante

Se utilizzi S3 Object Lambda, tutte le richieste a S3 Object Lambda vengono firmate tramite s3-object-lambda anziché s3. Questo comportamento influisce sulla firma dei valori di checksum finali. Per ulteriori informazioni su Lambda per oggetti S3, consulta Trasformazione di oggetti con S3 Object Lambda.

Intestazioni di checksum finali

Per effettuare una richiesta di codifica del contenuto in blocchi, Amazon S3 richiede che i server client includano diverse intestazioni per analizzare correttamente la richiesta. I server client devono includere le intestazioni seguenti:

  • x-amz-decoded-content-length: questa intestazione indica la dimensione in testo normale dei dati effettivi che vengono caricati su Amazon S3 con la richiesta.

  • x-amz-content-sha256: questa intestazione indica il tipo di caricamento in blocchi incluso nella richiesta. Per i caricamenti in blocchi con checksum finali, il valore dell’intestazione è STREAMING-UNSIGNED-PAYLOAD-TRAILER per le richieste che non utilizzano la firma del payload e STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER per le richieste che utilizzano la firma del payload SigV4. Per ulteriori informazioni sull’implementazione dei payload firmati, consulta Calcoli della firma per l’intestazione di autorizzazione: trasferimento di un payload in più blocchi.

  • x-amz-trailer: questa intestazione indica il nome dell’intestazione finale nella richiesta. Se esistono checksum finali (in cui gli AWS SDK aggiungono i checksum ai corpi della richiesta codificata), il valore dell’intestazione x-amz-trailer include il prefisso x-amz-checksum- e termina con il nome dell’algoritmo. Attualmente sono supportati i seguenti valori x-amz-trailer:

    • x-amz-checksum-crc32

    • x-amz-checksum-crc32c

    • x-amz-checksum-crc64nvme

    • x-amz-checksum-sha1

    • x-amz-checksum-sha256

Nota

Puoi anche includere nella richiesta l’intestazione Content-Encoding, con il valore in blocchi. Sebbene questa intestazione non sia obbligatoria, la sua specifica può ridurre i problemi del proxy HTTP durante la trasmissione di dati codificati. Se nella richiesta è presente un’altra intestazione Content-Encoding (come gzip), l’intestazione Content-Encoding include il valore in blocchi in un elenco di codifiche separate da virgole. Ad esempio, Content-Encoding: aws-chunked, gzip.

Parti in blocchi

Quando carichi un oggetto su Amazon S3 utilizzando la codifica in blocchi, la richiesta di caricamento include i seguenti tipi di blocchi (formattati nell’ordine elencato):

  • Blocchi del corpo dell’oggetto: a una richiesta di caricamento in blocchi possono essere associati uno, più o zero blocchi del corpo.

  • Blocchi di completamento: a una richiesta di caricamento in blocchi possono essere associati uno, più o zero blocchi del corpo.

  • Blocchi finali: il checksum finale viene elencato dopo il blocco di completamento. È consentito un solo blocco finale.

Nota

Ogni caricamento in blocchi deve terminare con un CRLF finale (ad esempio \r\n) per indicare la fine della richiesta.

Per esempi di formattazione in blocchi, consulta Esempi: caricamenti in blocchi con checksum finali.

Blocchi del corpo dell’oggetto

I blocchi del corpo dell’oggetto sono i blocchi che contengono i dati effettivi dell’oggetto che vengono caricati su S3. Questi blocchi hanno vincoli di dimensione e formato coerenti.

Dimensione dei blocchi del corpo dell’oggetto

Questi blocchi devono contenere almeno 8.192 byte (o 8 KiB) di dati dell’oggetto, ad eccezione del blocco del corpo finale, che può essere più piccolo. Non esiste una dimensione massima esplicita dei blocchi, ma è necessario che tutti i blocchi siano inferiori alla dimensione massima di caricamento di 5 GB. Le dimensioni dei blocchi possono variare da un blocco all’altro in base all’implementazione del server client.

Formato dei blocchi del corpo dell’oggetto

I blocchi del corpo dell’oggetto iniziano con la codifica esadecimale del numero di byte nel blocco del corpo dell’oggetto, seguita da un CRLF (Carriage Return Line Feed, ritorno a capo con avanzamento riga), dai byte dell’oggetto per il blocco e da un altro CRLF.

Ad esempio:

hex-encoding-of-object-bytes-in-chunk\r\n chunk-object-bytes\r\n

Tuttavia, quando il blocco è firmato, il blocco del corpo dell’oggetto segue un formato diverso, in cui la firma viene aggiunta alla dimensione del blocco con un punto e virgola come delimitatore. Ad esempio:

hex-encoding-of-object-bytes-in-chunk;chunk-signature\r\n chunk-object-bytes\r\n

Per ulteriori informazioni sulla firma dei blocchi, consulta Calcoli della firma per l’intestazione Authorization: trasferimento di un payload in più blocchi (AWS Signature Version 4). Per ulteriori informazioni sulla formattazione dei blocchi, consulta Chunked transfer encoding sul sito web RFC Editor.

Blocchi di completamento

I blocchi di completamento devono essere il blocco finale del corpo dell’oggetto di ogni caricamento in blocchi. Il formato di un blocco di completamento è simile a quello del blocco del corpo, ma contiene sempre zero byte di dati dell’oggetto. Gli zero byte dei dati dell’oggetto indicano che tutti i dati sono stati caricati. I caricamenti in blocchi devono includere un blocco di completamento come blocco finale del corpo dell’oggetto, secondo un formato come il seguente:

0\r\n

Tuttavia, se la richiesta di codifica del contenuto utilizza la firma del payload, il formato è il seguente:

0;chunk-signature\r\n

Blocchi finali

I blocchi finali contengono il checksum calcolato per tutte le richieste di caricamento S3. I blocchi finali includono due campi: un campo con il nome dell’intestazione e un campo con il valore dell’intestazione. Il campo del nome dell’intestazione per una richiesta di caricamento deve corrispondere al valore passato nell’intestazione della richiesta x-amz-trailer. Ad esempio, se una richiesta contiene x-amz-trailer: x-amz-checksum-crc32 e il blocco finale ha il nome dell’intestazione x-amz-checksum-sha1, la richiesta ha esito negativo. Il campo del valore nel blocco finale include una codifica in base64 del valore di checksum big-endian per l’oggetto. L’ordinamento big-endian archivia il byte di dati più significativo nell’indirizzo di memoria più basso e il byte meno significativo nell’indirizzo di memoria più alto. L’algoritmo utilizzato per calcolare questo checksum è lo stesso del suffisso per il nome dell’intestazione (ad esempio, crc32).

Formato del blocco finale

I blocchi finali utilizzano il seguente formato per le richieste di payload non firmate:

x-amz-checksum-lowercase-checksum-algorithm-name:base64-checksum-value\n\r\n\r\n

Per le richieste con payload firmati SigV4, il blocco finale include una firma finale dopo il blocco finale.

trailer-checksum\n\r\n trailer-signature\r\n

Puoi anche aggiungere il CRLF direttamente alla fine del valore di checksum in base64. Ad esempio:

x-amz-checksum-lowercase-checksum-algorithm-name:base64-checksum-value\r\n\r\n

Esempi: caricamenti in blocchi con checksum finali

Amazon S3 supporta i caricamenti in blocchi che utilizzano la codifica dei contenuti aws-chunked per le richieste PutObject e UploadPart con checksum finali.

Esempio 1: richiesta PutObject in blocchi non firmati con checksum CRC-32 finale

Di seguito è illustrato un esempio di richiesta PutObject in blocchi con checksum CRC-32 finale. In questo esempio, il client carica un oggetto da 17 KB in tre blocchi non firmati e aggiunge un blocco di checksum CRC-32 finale utilizzando l’intestazione x-amz-checksum-crc32.

PUT /Key+ HTTP/1.1 Host: amzn-s3-demo-bucket Content-Encoding: aws-chunked x-amz-decoded-content-length: 17408 x-amz-content-sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER x-amz-trailer: x-amz-checksum-crc32 2000\r\n // Object body chunk 1 (8192 bytes) object-bytes\r\n 2000\r\n // Object body chunk 2 (8192 bytes) object-bytes\r\n 400\r\n // Object body chunk 3 (1024 bytes) object-bytes\r\n 0\r\n // Completion chunk x-amz-checksum-crc32:YABb/g==\n\r\n\r\n // Trailer chunk (note optional \n character) \r\n // CRLF

Ecco un esempio di risposta:

HTTP/1.1 200 ETag: ETag x-amz-checksum-crc32: YABb/g==
Nota

L’utilizzo dell’avanzamento riga \n alla fine del valore di checksum può variare tra i client.

Esempio 2: richiesta PutObject in blocchi firmati da SigV4 con un checksum CRC-32 (CRC32) finale

Di seguito è illustrato un esempio di richiesta PutObject in blocchi con checksum CRC-32 finale. Questa richiesta utilizza la firma del payload SigV4. In questo esempio, il client carica un oggetto da 17 KB in tre blocchi firmati. Oltre ai blocchi object body, vengono firmati anche completion chunk e trailer chunk.

PUT /Key+ HTTP/1.1 Host: amzn-s3-demo-bucket.s3.amazonaws.com Content-Encoding: aws-chunked x-amz-decoded-content-length: 17408 x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER x-amz-trailer: x-amz-checksum-crc32 authorization-code // SigV4 headers authorization 2000;chunk-signature=signature-value...\r\n // Object body chunk 1 (8192 bytes) object-bytes\r\n 2000;chunk-signature\r\n // Object body chunk 2 (8192 bytes) object-bytes\r\n 400;chunk-signature\r\n // Object body chunk 3 (1024 bytes) object-bytes\r\n 0;chunk-signature\r\n // Completion chunk x-amz-checksum-crc32:YABb/g==\n\r\n // Trailer chunk (note optional \n character) trailer-signature\r\n \r\n // CRLF

Ecco un esempio di risposta:

HTTP/1.1 200 ETag: ETag x-amz-checksum-crc32: YABb/g==