Vérification de l’intégrité des objets lors de chargements de données dans Amazon S3 - Amazon Simple Storage Service

Vérification de l’intégrité des objets lors de chargements de données dans Amazon S3

Amazon S3 utilise des valeurs de somme de contrôle pour vérifier l’intégrité des données pendant les opérations de chargement et de téléchargement. Lorsque vous chargez des données, le kit AWS SDK et la AWS Management Console utilisent l’algorithme de somme de contrôle que vous avez choisi pour calculer une valeur de somme de contrôle avant la transmission des données. S3 calcule ensuite indépendamment une somme de contrôle de vos données et la valide par rapport à la valeur de contrôle fournie. Les objets ne sont acceptés qu’après confirmation de l’intégrité des données pendant le transit. S3 stocke à la fois la valeur de la somme de contrôle sous forme de métadonnées d’objet et l’objet lui-même.

Pour vérifier l’intégrité d’un objet, vous pouvez demander la valeur de la somme de contrôle lors du téléchargement. Cette validation fonctionne de manière cohérente quels que soient les modes de chiffrement, les tailles d’objets, les classes de stockage et le type de chargement (partitionné ou non). Pour modifier l’algorithme de somme de contrôle d’un chargement, vous pouvez copier un objet, ou utiliser la copie par lot si vous possédez plusieurs objets.

Pour les chargements non partitionnés, vous pouvez fournir des valeurs de somme de contrôle sous forme d’en-têtes. Vous pouvez soit fournir une valeur précalculée, soit laisser le kit AWS SDK en calculer une lors du chargement. Si la valeur de la somme de contrôle calculée par S3 correspond à la valeur que vous avez fournie, la demande est acceptée. Si les valeurs ne correspondent pas, la demande est refusée.

Pour les chargements fragmentés, les kits AWS SDK peuvent créer automatiquement des sommes de contrôle de fin. Lorsque vous utilisez une somme de contrôle de fin, Amazon S3 génère des valeurs de somme de contrôle pour chaque partie à l’aide de l’algorithme que vous avez spécifié, et ajoute la valeur de somme de contrôle à la fin de la demande de chargement fragmenté. S3 effectue la vérification et le chargement en une seule fois, ce qui accroît l’efficacité. Pour plus d’informations, consultez Utilisation des totaux de contrôle de fin.

Utilisation des algorithmes de somme de contrôle pris en charge

Avec Amazon S3, vous pouvez choisir un algorithme de somme de contrôle pour calculer les valeurs de somme de contrôle lors des chargements. L’algorithme de somme de contrôle spécifié est ensuite stocké avec l’objet et peut être utilisé pour valider l’intégrité des données lors des chargements. Vous pouvez sélectionner l’un des algorithmes suivants de somme de contrôle Secure Hash Algorithms (SHA) ou Cyclic Redundancy Check (CRC) pour calculer la valeur de la somme de contrôle :

  • CRC-64/NVME (CRC64NVME)

  • CRC-32 (CRC32)

  • CRC-32C (CRC32C)

  • SHA-1 (SHA1)

  • SHA-256 (SHA256)

  • MD5 (MD5)

    Note

    L’en-tête content-MD5 n’est disponible qu’avec la balise d’entité S3 des objets chargés dans le cadre d’un chargement non partitionné (opération PUT) qui utilise le chiffrement SSE-S3.

En outre, vous pouvez fournir une somme de contrôle pour chaque demande à l’aide de l’en-tête Content-MD5.

Lorsque vous chargez un objet, vous spécifiez l’algorithme que vous souhaitez utiliser :

  • Lorsque vous utilisez la AWS Management Console, sélectionnez l’algorithme de somme de contrôle que vous souhaitez utiliser. Vous avez la possibilité de spécifier la valeur de la somme de contrôle de l’objet. Lorsque Amazon S3 reçoit l’objet, il calcule le total de contrôle en utilisant l’algorithme que vous avez spécifié. Si les deux valeurs ne correspondent pas, Amazon S3 génère une erreur.

  • Lorsque vous utilisez un kit SDK, gardez à l’esprit les points suivants :

    • Définissez le paramètre ChecksumAlgorithm selon l’algorithme que vous souhaitez qu’Amazon S3 utilise. Si vous disposez déjà d’une somme de contrôle précalculée, transmettez sa valeur au kit AWS SDK, qui l’inclura dans la demande. Si vous ne transmettez pas de valeur de somme de contrôle ou ne spécifiez pas d’algorithme de somme de contrôle, le kit SDK calculera automatiquement une valeur de somme de contrôle pour vous et l’inclura dans la demande afin de fournir des protections d’intégrité. Si la valeur de somme de contrôle individuelle ne correspond pas à la valeur définie par l’algorithme de somme de contrôle, Amazon S3 abandonne la demande avec une erreur BadDigest.

    • Si vous utilisez un kit AWS SDK mis à niveau, celui-ci choisit un algorithme de somme de contrôle pour vous. Vous pouvez toutefois remplacer cet algorithme.

    • Si vous ne spécifiez pas d’algorithme de somme de contrôle et que le kit SDK ne calcule pas non plus de somme de contrôle pour vous, S3 choisit automatiquement l’algorithme de somme de contrôle CRC-64/NVME (CRC64NVME).

  • Lorsque vous utilisez l’API REST, n’utilisez pas le paramètre x-amz-sdk-checksum-algorithm. Utilisez plutôt l’un des en-têtes spécifiques à l’algorithme (par exemple, x-amz-checksum-crc32).

Pour appliquer ces valeurs de somme de contrôle à des objets déjà chargés sur Amazon S3, vous pouvez copier l’objet et spécifier si vous voulez utiliser l’algorithme de somme de contrôle existant ou un autre. Si vous ne spécifiez aucun algorithme, S3 utilise l’algorithme existant. Si l’objet source ne possède pas d’algorithme de somme de contrôle ou de valeur de somme de contrôle spécifié, Amazon S3 utilise l’algorithme CRC-64/NVME pour calculer la valeur de somme de contrôle de l’objet de destination. Vous pouvez spécifier un algorithme de somme de contrôle lors de la copie d’objets à l’aide de S3 Batch Operations.

Important

Si vous utilisez un chargement partitionné avec Sommes de contrôle pour des sommes de contrôle composites (ou au niveau de chaque partie), les numéros de chaque partie du chargement partitionné doivent être consécutifs et commencer par 1. Si vous essayez de finaliser une demande de chargement partitionné avec des numéros de partie non consécutifs, Amazon S3 génère une erreur HTTP 500 Internal Server.

Types de sommes de contrôle d’objet entier et composites

Dans Amazon S3, deux types de sommes de contrôle sont pris en charge :

  • Sommes de contrôle des objets entiers : la somme de contrôle d’un objet entier est calculée sur la base de l’ensemble du contenu d’un chargement partitionné, couvrant toutes les données allant du premier octet de la première partie chargée au dernier octet de la dernière partie chargée. Sachez que si vous utilisez la AWS Management Console pour charger des objets de moins de 16 Mo, seul le type de somme de contrôle de l’objet complet est pris en charge.

    Note

    Toutes les demandes PUT nécessitent un type de somme de contrôle d’objet entier. Vous devez spécifier le type de somme de contrôle de l’objet complet si vous chargez votre objet via une demande PUT.

  • Sommes de contrôle composites : une somme de contrôle composite est calculée sur la base des sommes de contrôle individuelles de chaque partie d’un chargement partitionné. Au lieu de calculer une somme de contrôle basée sur l’ensemble du contenu des données, cette approche agrège les sommes de contrôle au niveau de chaque partie (de la première à la dernière) afin de générer une somme de contrôle unique combinée pour l’objet entier. Si vous utilisez un chargement partitionné pour charger votre objet, vous devez spécifier le type de somme de contrôle composite.

    Note

    Lorsqu’un objet est chargé sous forme de chargement partitionné, sa balise d’entité n’est pas un condensé d’octets MD5 de l’objet entier. Amazon S3 calcule le condensé d’octets MD5 de chaque partie au fur et à mesure qu’elle est chargée. Les récapitulatifs MD5 sont utilisés pour déterminer la balise ETag de l’objet final. Amazon S3 concatène les octets des récapitulatifs MD5, puis calcule le récapitulatif MD5 de ces valeurs concaténées. Lors de l’étape finale de création de la balise d’entité, Amazon S3 ajoute à la fin un tiret avec le nombre total de parties.

Amazon S3 prend en charge les types de sommes de contrôle d’objet entier et les types de sommes de contrôle composites suivants :

  • CRC-64/NVME (CRC64NVME) : prend en charge le type de somme de contrôle de l’objet complet uniquement.

  • CRC-32 (CRC32) : prend en charge à la fois le type de somme de contrôle de l’objet complet et le type de somme de contrôle composite.

  • CRC-32C (CRC32C) : prend en charge à la fois le type de somme de contrôle de l’objet complet et le type de somme de contrôle composite.

  • SHA-1 (SHA1) : prend en charge à la fois le type de somme de contrôle de l’objet complet et le type de somme de contrôle composite.

  • SHA-256 (SHA256) : prend en charge à la fois le type de somme de contrôle de l’objet complet et le type de somme de contrôle composite.

  • MD5 (MD5) : prend en charge à la fois le type de somme de contrôle de l’objet complet et le type de somme de contrôle composite.

Chargements en une seule partie

Les sommes de contrôle des objets chargés en une seule partie (à l’aide de PutObject) sont traitées comme des sommes de contrôle d’objets entiers. Lorsque vous chargez un objet dans la console Amazon S3, vous pouvez choisir l’algorithme de somme de contrôle que vous souhaitez que S3 utilise et, si vous le souhaitez, vous pouvez aussi fournir une valeur précalculée. Amazon S3 valide ensuite la valeur précalculée de la somme de contrôle avant de la stocker avec l’objet. Vous pouvez vérifier l’intégrité des données d’un objet lorsque vous demandez la valeur de la somme de contrôle lors du chargement de l’objet.

Chargements partitionnés

Lorsque vous chargez l’objet en plusieurs parties à l’aide de l’API MultipartUpload, vous pouvez spécifier l’algorithme de somme de contrôle que vous souhaitez qu’Amazon S3 utilise et le type de somme de contrôle (objet entier ou composite).

Le tableau suivant indique quel type d’algorithme de somme de contrôle est pris en charge pour chaque algorithme de somme de contrôle d’un chargement partitionné :

Algorithme de somme de contrôle Objet complet Composite
CRC-64/NVME (CRC64NVME) Oui Non
CRC-32 (CRC32) Oui Oui
CRC-32C (CRC32C) Oui Oui
SHA-1 (SHA1) Non Oui
SHA-256 (SHA256) Non Oui

Utilisation des sommes de contrôle des objets entiers pour le chargement partitionné

Lorsque vous créez ou effectuez un chargement partitionné, vous pouvez utiliser les sommes de contrôle de l’objet entier pour la validation du chargement. Cela signifie que vous pouvez fournir l’algorithme de somme de contrôle pour l’API MultipartUpload, ce qui simplifie les outils de validation de l’intégrité, car vous n’avez plus besoin de suivre les limites de chaque partie pour les objets chargés. Vous pouvez fournir la somme de contrôle de l’objet entier dans la demande CompleteMultipartUpload, ainsi que la taille de l’objet.

Lorsque vous fournissez la somme de contrôle d’un objet entier lors d’un chargement partitionné, le kit AWS SDK transmet cette somme de contrôle à Amazon S3, puis S3 valide l’intégrité de l’objet côté serveur, en la comparant à la valeur reçue. Amazon S3 stocke ensuite l’objet si les valeurs correspondent. Si les deux valeurs ne correspondent pas, S3 fait échouer la demande et génère une erreur BadDigest. La somme de contrôle de votre objet est également stockée dans les métadonnées de l’objet que vous utiliserez ultérieurement pour valider l’intégrité des données d’un objet.

Pour les sommes de contrôle d’un objet complet, vous pouvez utiliser l’algorithme de somme de contrôle CRC-64/NVME (CRC64NVME), CRC-32 (CRC32) ou CRC-32C (CRC32C) dans S3. Les sommes de contrôle des objets entiers dans les chargements partitionnés ne sont disponibles que pour les sommes de contrôle basées sur l’algorithme CRC, car elles peuvent être linéarisées en une somme de contrôle pour l’objet entier. Cette linéarisation permet à Amazon S3 de paralléliser vos demandes pour améliorer les performances. S3 peut notamment calculer la somme de contrôle de l’objet entier à partir des sommes de contrôle au niveau de chaque partie. Ce type de validation n’est pas disponible pour les autres algorithmes, tels que SHA et MD5. Comme S3 dispose de protections d’intégrité par défaut, si des objets sont chargés sans somme de contrôle, S3 attache automatiquement l’algorithme recommandé de somme de contrôle de l’objet complet CRC-64/NVME (CRC64NVME) à l’objet.

Note

Pour lancer le chargement partitionné, vous pouvez spécifier l’algorithme de somme de contrôle et le type de somme de contrôle de l’objet entier. Après avoir spécifié l’algorithme de somme de contrôle et le type de somme de contrôle de l’objet entier, vous pouvez fournir la valeur de somme de contrôle de cet objet pour le chargement partitionné.

Utilisation des sommes de contrôle au niveau des parties d’un chargement partitionné

Lorsque des objets sont chargés sur Amazon S3, ils peuvent être chargés en tant qu’objet unique ou en plusieurs parties par le biais du processus de chargement partitionné. Vous pouvez choisir un type de somme de contrôle pour votre chargement partitionné. Pour les sommes de contrôle au niveau de chaque partie d’un chargement partitionné (ou les sommes de contrôle composites), Amazon S3 calcule la somme de contrôle pour chaque partie en utilisant l’algorithme de somme de contrôle spécifié. Vous pouvez utiliser UploadPart pour fournir les valeurs de somme de contrôle pour chaque partie. Si l’objet que vous essayez de charger dans la console Amazon S3 est configuré pour utiliser l’algorithme de somme de contrôle CRC-64/NVME (CRC64NVME) et qu’il dépasse 16 Mo, il est automatiquement désigné comme somme de contrôle d’objet complet.

Amazon S3 utilise ensuite les valeurs de somme de contrôle stockées au niveau de chaque partie pour confirmer que chacune d’elle est correctement chargée. Lorsque la somme de contrôle de chaque partie (de l’objet entier) est fournie, S3 utilise les valeurs de la somme de contrôle stockées pour chaque partie afin de calculer la somme de contrôle de l’objet entier en interne, en la comparant à la valeur de la somme de contrôle fournie. Les coûts de calcul sont ainsi réduits, car S3 peut calculer une somme de contrôle de l’objet entier en utilisant la somme de contrôle de chaque partie. Pour en savoir plus sur les chargements partitionnés, consultez Chargement et copie d’objets à l’aide du chargement partitionné dans Amazon S3 et Utilisation des sommes de contrôle des objets entiers pour le chargement partitionné.

Lorsque l’objet est complètement chargé, vous pouvez utiliser la somme de contrôle finale calculée pour vérifier l’intégrité des données de l’objet.

Lors du chargement d’une partie du chargement partitionné, tenez compte des points suivants :

  • Pour extraire des informations sur l’objet, notamment le nombre de parties qui le composent, vous pouvez utiliser l’opération GetObjectAttributes. Avec les sommes de contrôle supplémentaires, vous pouvez également récupérer des informations pour chaque partie individuelle, y compris la valeur de la somme de contrôle de chaque partie.

  • Pour les chargements finalisés, vous pouvez obtenir la somme de contrôle d’une partie individuelle à l’aide des opérations GetObject ou HeadObject et en spécifiant un numéro de partie ou une plage d’octets qui correspond à sur une seule partie. Pour récupérer les valeurs de somme de contrôle de chaque partie des chargements partitionnés qui sont toujours en cours, vous pouvez utiliser ListParts.

  • En raison de la façon dont Amazon S3 calcule le total de contrôle pour les objets à plusieurs parties, la valeur du total de contrôle de l’objet peut changer si vous le copiez. Si vous utilisez un kit SDK ou l’API REST et que vous appelez CopyObject, Amazon S3 copie tout objet conformément aux limites de taille de l’opération API CopyObject. Amazon S3 effectue cette copie en une seule action, que l’objet ait été chargé en une seule requête ou dans le cadre d’un chargement partitionné. Avec une commande de copie, le total de contrôle de l’objet est un total de contrôle direct de l’objet complet. Si l’objet a été initialement chargé à l’aide d’un chargement partitionné, la valeur de la somme de contrôle change même si les données ne changent pas.

  • Les objets dont la taille dépasse les limites de l’opération d’API CopyObject doivent utiliser des commandes de copie par chargement partitionné.

  • Lorsque vous effectuez certaines opérations à l’aide de la fonction de la AWS Management Console, Amazon S3 utilise un chargement partitionné si la taille de l’objet est supérieure à 16 Mo.

Méthodes de somme de contrôle

Après avoir chargé des objets, vous pouvez obtenir la valeur de la somme de contrôle et la comparer à une valeur de somme de contrôle précalculée ou précédemment stockée pour le même type d’algorithme de somme de contrôle. Les exemples suivants illustrent les opérations ou méthodes de calcul de somme de contrôle que vous pouvez utiliser pour vérifier l’intégrité des données.

Pour en savoir plus sur l’utilisation de la console et la définition des algorithmes de somme de contrôle à utiliser lors du chargement d’objets, consultez Chargement d’objets et Didacticiel : Vérification de l’intégrité des données dans Amazon S3 avec des sommes de contrôle supplémentaires.

L’exemple suivant montre comment utiliser les kits AWS SDK pour charger un fichier volumineux avec un chargement partitionné, télécharger un fichier volumineux et valider un fichier de chargement partitionné, le tout en utilisant SHA-256 pour la validation du fichier.

Java
Exemple : chargement, téléchargement et vérification d’un fichier volumineux avec SHA-256

Pour obtenir les instructions pour la création et le test d’un exemple pratique, consultez Démarrer dans le Guide du développeur AWS SDK pour 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(); } } }

Vous pouvez envoyer des requêtes REST pour charger un objet avec une valeur de total de contrôle pour vérifier l’intégrité des données avec PutObject. Vous pouvez également extraire la valeur de total de contrôle pour les objets à l’aide de la fonctionnalité GetObject ou HeadObject.

Vous pouvez envoyer une demande PUT pour télécharger un objet d’une taille maximale de 5 Go en une seule opération. Pour plus d’informations, reportez-vous à la section PutObject dans la Référence des commandes de l’AWS CLI. Vous pouvez également utiliser get-object et head-object pour récupérer le total de contrôle d’un objet déjà chargé afin de vérifier l’intégrité des données.

Pour plus d’informations, consultez la FAQ de l’interface de ligne de commande Amazon S3 dans le Guide de l’utilisateur AWS Command Line Interface.

Utilisation de Content-MD5 pour charger des objets

Une autre façon de vérifier l’intégrité de votre objet après le chargement est de fournir un récapitulatif MD5 de l’objet lorsque vous le chargez. Si vous calculez le récapitulatif MD5 de votre objet, vous pouvez fournir ce récapitulatif avec la commande PUT en utilisant l’en-tête Content-MD5.

Après avoir chargé l’objet, Amazon S3 calcule le récapitulatif MD5 de l’objet et le compare à la valeur que vous avez fournie. La requête n’aboutit que si les deux récapitulatifs correspondent.

La fourniture d’un récapitulatif MD5 n’est pas obligatoire, mais vous pouvez l’utiliser pour vérifier l’intégrité de l’objet dans le cadre du processus de chargement.

Utilisation de Content-MD5 et de ETag pour vérifier les objets chargés.

Le balise d’entité (ETag) d’un objet représente une version spécifique de cet objet. Gardez à l’esprit que la balise d’entité ne reflète que les changements apportés au contenu d’un objet et non à ses métadonnées. Si seules les métadonnées d’un objet changent, la balise ETag reste le même.

Selon l’objet, la balise ETag de l’objet peut être un récapitulatif MD5 des données de l’objet :

  • Si un objet est créé par l’opération PutObject, PostObject, ou CopyObject, ou via la AWS Management Console et que cet objet est également en texte brut ou chiffré par un chiffrement côté serveur avec des clés gérées par Amazon S3 (SSE-S3), cet objet possède un ETag qui est un récapitulatif MD5 de ses données.

  • Si un objet est créé par l’opération PutObject, PostObject, ou CopyObject, ou par le AWS Management Console et que cet objet est chiffré par un chiffrement côté serveur avec des clés fournies par le client (SSE-C) ou un chiffrement côté serveur avec des clés AWS Key Management Service (AWS KMS) (SSE-KMS), cet objet a un ETag qui n’est pas un récapitulatif MD5 de ses données d’objet.

  • Si un objet est créé par le processus de chargement partitionné ou l’opération UploadPartCopy, sa balise d’entité n’est pas un condensé d’octets MD5, quelle que soit la méthode de chiffrement. Si un objet est plus grand que 16 Mo, le chargement AWS Management Console ou la copie de cet objet est un chargement partitionné et la balise ETag n’est pas un récapitulatif MD5.

Pour les objets où la balise ETag est le récapitulatif Content-MD5 de l’objet, vous pouvez comparer la valeur ETag de l’objet avec un récapitulatif Content-MD5 calculé ou précédemment stocké.

Utilisation des totaux de contrôle de fin

Lorsque vous chargez des objets volumineux dans Amazon S3, vous pouvez soit fournir une somme de contrôle précalculée pour l’objet, soit utiliser un kit AWS SDK pour créer automatiquement en votre nom des sommes de contrôle de fin pour les chargements fragmentés. Si vous utilisez une somme de contrôle de fin, Amazon S3 génère automatiquement la valeur de somme de contrôle en utilisant l’algorithme que vous avez spécifié pour valider l’intégrité de l’objet pendant le chargement fragmenté.

Pour créer un total de contrôle de fin lors de l’utilisation d’un kit AWS SDK, remplissez le paramètre ChecksumAlgorithm avec votre algorithme préféré. Le kit SDK utilise cet algorithme pour calculer la valeur de somme de contrôle de votre objet (ou de ses parties), et l’ajoute automatiquement à la fin de votre demande de chargement fragmenté. Ce comportement vous fait gagner du temps, car Amazon S3 effectue la vérification et le chargement de vos données en une seule opération.

Important

Si vous utilisez S3 Object Lambda, toutes les requêtes adressées à S3 Object Lambda sont signées en utilisant s3-object-lambda au lieu de s3. Ce comportement affecte la signature des valeurs de total de contrôle de fin. Pour en savoir plus sur S3 Object Lambda, consultez Transformation d’objets avec S3 Object Lambda.

En-têtes des sommes de contrôle de fin

Pour effectuer une demande de codage de contenu fragmenté, Amazon S3 exige que les serveurs clients incluent plusieurs en-têtes afin d’analyser correctement la demande. Les serveurs clients doivent inclure les en-têtes suivants :

  • x-amz-decoded-content-length : cet en-tête indique la taille du texte brut des données réelles qui sont chargées dans Amazon S3 avec la demande.

  • x-amz-content-sha256 : cet en-tête indique le type de chargement fragmenté inclus dans la demande. Pour les chargements fragmentés avec des sommes de contrôle de fin, la valeur de l’en-tête est STREAMING-UNSIGNED-PAYLOAD-TRAILER pour les demandes qui n’utilisent pas de signature de données utiles et STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER pour les demandes qui utilisent la signature de données utiles SigV4. (Pour plus d’informations sur la mise en œuvre de données utiles signées, consultez Calcul des signatures pour l’en-tête d’autorisation : transfert fragmenté des données utiles.)

  • x-amz-trailer : cet en-tête indique le nom de l’en-tête de fin de la demande. S’il existe des sommes de contrôle de fin (lorsque les kits AWS SDK ajoutent des sommes de contrôle aux corps codés des demandes), la valeur de l’en-tête x-amz-trailer inclut le préfixe x-amz-checksum- et se termine par le nom de l’algorithme. Les valeurs x-amz-trailer suivantes sont actuellement prises en charge :

    • x-amz-checksum-crc32

    • x-amz-checksum-crc32c

    • x-amz-checksum-crc64nvme

    • x-amz-checksum-sha1

    • x-amz-checksum-sha256

Note

Vous pouvez également inclure l’en-tête Content-Encoding, avec la valeur fragmentée, dans votre demande. Bien que cet en-tête ne soit pas obligatoire, son ajout peut réduire les problèmes de proxy HTTP lors de la transmission de données codées. S’il existe un autre en-tête Content-Encoding (tel que gzip) dans la demande, l’en-tête Content-Encoding inclut la valeur fragmentée dans une liste de codages séparés par des virgules. Par exemple, Content-Encoding: aws-chunked, gzip.

Parties fragmentées

Lorsque vous chargez un objet dans Amazon S3 à l’aide d’un codage fragmenté, la demande de chargement inclut les types de fragments suivants (dans l’ordre indiqué) :

  • Fragments du corps de l’objet : une demande de chargement fragmenté peut être associée à un, plusieurs ou aucun fragment de corps.

  • Fragments d’achèvement : une demande de chargement fragmenté peut être associée à un, plusieurs ou aucun fragment de corps.

  • Fragments de fin : la somme de contrôle de fin est indiquée après le fragment de fin. Un seul fragment de fin est autorisé.

Note

Chaque chargement fragmenté doit se terminer par un CRLF (tel que \r\n) pour indiquer la fin de la demande.

Pour voir des exemples de mise en forme fragmentée, consultez Exemples : chargements fragmentés avec des sommes de contrôle de fin.

Fragments du corps d’un objet

Les fragments du corps de l’objet sont les fragments qui contiennent les données réelles de l’objet qui sont chargées dans S3. Ces fragments sont soumis à des contraintes de cohérence de taille et de format.

Taille des fragments du corps d’un objet

Ces fragments doivent contenir au moins 8 192 octets (ou 8 Kio) de données de l’objet, à l’exception du dernier fragment du corps, qui peut être plus petit. Il n’y a pas de taille maximale explicite, mais tous les fragments doivent être inférieurs à la taille de chargement maximale de 5 Go. La taille peut varier d’un fragment à l’autre en fonction de l’implémentation de votre serveur client.

Format des fragments du corps d’un objet

Les fragments du corps d’un objet commencent par le codage hexadécimal du nombre d’octets qu’ils contiennent, suivi d’un CRLF (Carriage Return Line Feed), des octets de l’objet correspondant à ce fragment et d’un autre CRLF.

Par exemple :

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

Toutefois, lorsque le fragment est signé, le fragment du corps de l’objet adopte un format différent, dans lequel la signature est ajoutée à la taille du fragment avec un point-virgule. Par exemple :

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

Pour plus d’informations sur la signature des fragments, consultez Calcul des signatures pour l’en-tête Authorization : transfert fragmenté des données utiles (AWSSignature version 4). Pour plus d’informations sur le formatage des fragments, consultez Chunked transfer encoding sur le site Web de RFC Editor.

Fragments d’achèvement

Les fragments d’achèvement doivent être le dernier fragment du corps de l’objet de chaque chargement fragmenté. Le format d’un fragment d’achèvement est semblable à celui d’un fragment du corps, mais il ne contient jamais aucun octet de données de l’objet. (Cette absence d’octet de données de l’objet indique que toutes les données ont été chargées.) Les chargements fragmentés doivent inclure un fragment d’achèvement comme dernier fragment du corps de l’objet, selon un format comme celui-ci :

0\r\n

Toutefois, si la demande de codage de contenu utilise la signature des données utiles, elle suit plutôt le format suivant :

0;chunk-signature\r\n

Fragments de fin

Les fragments de fin contiennent la somme de contrôle calculée pour toutes les demandes de chargement S3. Ils incluent deux champs : un champ de nom d’en-tête et un champ de valeur d’en-tête. Le champ du nom d’en-tête d’une demande de chargement doit correspondre à la valeur transmise dans l’en-tête de la demande x-amz-trailer. Par exemple, si une demande contient x-amz-trailer: x-amz-checksum-crc32 et le fragment de fin comprend le nom d’en-tête x-amz-checksum-sha1, la demande échoue. Le champ de valeur du fragment de fin inclut un codage base64 de la valeur de la somme de contrôle gros-boutiste de cet objet. (L’ordre gros-boutiste stocke l’octet le plus significatif des données à l’adresse mémoire la plus basse, et l’octet le moins significatif à l’adresse mémoire la plus élevée). L’algorithme utilisé pour calculer cette somme de contrôle est le même que le suffixe du nom d’en-tête (par exemple, crc32).

Format des fragments de fin

Les fragments de fin utilisent le format suivant pour les demandes de données utiles non signées :

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

Pour les demandes contenant des données utiles signées SigV4, le fragment de fin se termine par une signature de fin.

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

Vous pouvez également ajouter le CRLF directement à la fin de la valeur de la somme de contrôle base64. Par exemple :

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

Exemples : chargements fragmentés avec des sommes de contrôle de fin

Amazon S3 prend en charge les chargements fragmentés qui utilisent le codage de contenu aws-chunked pour les demandes PutObject et UploadPart avec des sommes de contrôle de fin.

Exemple 1 — Demande PutObject fragmentée non signée avec une somme de contrôle de fin CRC-32

Voici un exemple de demande PutObject fragmentée avec une somme de contrôle de fin CRC-32. Dans cet exemple, le client charge un objet de 17 Ko en trois fragments non signés et ajoute un bloc de somme de contrôle de fin CRC-32 en utilisant l’en-tête 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

Voici un exemple de réponse :

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

L’utilisation du saut de ligne \n à la fin de la valeur de la somme de contrôle peut varier selon les clients.

Exemple 2 — Demande PutObject fragmentée signée SigV4 avec une somme de contrôle de fin CRC-32 (CRC32)

Voici un exemple de demande PutObject fragmentée avec une somme de contrôle de fin CRC-32. Cette demande utilise la signature de données utiles SigV4. Dans cet exemple, le client charge un objet de 17 Ko en trois fragments signés. Outre les fragments object body les completion chunk et trailer chunk sont également signés.

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

Voici un exemple de réponse :

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