Comprobación de la integridad de objetos en Amazon S3 - Amazon Simple Storage Service

Comprobación de la integridad de objetos en Amazon S3

Amazon S3 utiliza valores de suma de comprobación para verificar la integridad de los datos que carga o descarga. Además, puede solicitar que se calcule otro valor de suma de comprobación para cualquier objeto que almacene en Amazon S3. Puede elegir un algoritmo de suma de comprobación para utilizarlo al cargar, copiar o copiar por lotes los datos.

Cuando carga los datos, Amazon S3 utiliza el algoritmo que ha elegido para calcular una suma de comprobación en el servidor y la valida con el valor proporcionado antes de almacenar el objeto y almacenar la suma de comprobación como parte de los metadatos del objeto. Esta validación funciona de forma coherente en todos los modos de cifrado, tamaños de objeto y clases de almacenamiento, tanto para cargas de una sola parte como de varias. No obstante, cuando copia o copia por lotes los datos, Amazon S3 calcula la suma de comprobación en el objeto de origen y lo mueve al objeto de destino.

nota

Cuando realiza una carga de una sola parte o de varias, puede incluir opcionalmente una suma de comprobación precalculada como parte de la solicitud y utilizar el tipo de suma de comprobación de objeto completo. Para utilizar valores precalculados con varios objetos, utilice la AWS CLI o los SDK de AWS.

Uso de algoritmos de suma de comprobación admitidos

Con Amazon S3, puede elegir un algoritmo de suma de comprobación para validar los datos durante las cargas. El algoritmo de suma de comprobación especificado se almacena con el objeto y puede utilizarse para validar la integridad de los datos durante las descargas. Puede elegir uno de los siguientes algoritmos de suma de comprobación de hash seguro (SHA) o de redundancia cíclica (CRC) para calcular el valor de suma de comprobación:

  • CRC-64/NVME (CRC64NVME)

  • CRC-32 (CRC32)

  • CRC-32C (CRC32C)

  • SHA-1 (SHA1)

  • SHA-256 (SHA256)

Además, puede proporcionar una suma de comprobación con cada solicitud mediante el encabezado Content-MD5.

Al cargar un objeto, especifique el algoritmo que desea utilizar:

  • Cuando utilice la AWS Management Console, elija el algoritmo de suma de comprobación que desee utilizar. Puede especificar opcionalmente el valor de la suma de comprobación del objeto. Cuando Amazon S3 recibe el objeto, calcula la suma de comprobación mediante el algoritmo especificado. Si los valores de la suma de comprobación no coinciden, Amazon S3 genera un error.

  • Al usar un SDK, tenga en cuenta lo siguiente:

    • Establezca el parámetro ChecksumAlgorithm en el algoritmo que desea que utilice Amazon S3. Si ya tiene una suma de comprobación precalculada, pase el valor al AWS SDK y el SDK incluirá el valor en la solicitud. Si no pasa un valor de suma de comprobación o no especifica un algoritmo de suma de comprobación, el SDK calcula automáticamente un valor de suma de comprobación y lo incluye con la solicitud para proporcionar protecciones de integridad. Si el valor de suma de comprobación individual no coincide con el valor establecido del algoritmo de suma de comprobación, Amazon S3 rechaza la solicitud con un error BadDigest.

    • Si está utilizando un SDK de AWS actualizado, el SDK elige un algoritmo de suma de comprobación por usted. No obstante, puede anular este algoritmo de suma de comprobación.

    • Si no especifica un algoritmo de suma de comprobación y el SDK tampoco calcula una suma de comprobación por usted, S3 elige automáticamente el algoritmo de suma de comprobación CRC-64/NVME (CRC64NVME).

  • Si utiliza la API de REST, no utilice el parámetro x-amz-sdk-checksum-algorithm. En su lugar, utilice uno de los encabezados específicos del algoritmo (por ejemplo, x-amz-checksum-crc32).

Para aplicar cualquiera de estos valores de suma de comprobación a objetos que ya se han cargado en Amazon S3, puede copiar el objeto y especificar si desea utilizar el algoritmo de suma de comprobación existente o uno nuevo. Si no especifica un algoritmo, S3 utiliza el algoritmo existente. Si el objeto de origen no tiene un algoritmo de suma de comprobación o un valor de suma de comprobación especificado, Amazon S3 utiliza el algoritmo CRC-64/NVME para calcular el valor de la suma de comprobación del objeto de destino. También puede especificar un algoritmo de suma de comprobación al copiar objetos mediante Operaciones por lotes de S3.

importante

Si utiliza una carga multiparte con Sumas de comprobación para sumas de comprobación compuestas (o a nivel de parte), los números de parte de la carga multiparte deben ser consecutivos y comenzar por 1. Si intenta completar una solicitud de carga multiparte con números de parte no consecutivos, Amazon S3 genera un error HTTP 500 Internal Server.

Tipos de suma de comprobación de objeto completo y compuesto

En Amazon S3, hay dos tipos de sumas de comprobación admitidas:

  • Sumas de comprobación de objeto completo: una suma de comprobación de objeto completo se calcula en función de todo el contenido de una carga multiparte, que abarca todos los datos desde el primer byte de la primera parte hasta el último byte de la última parte.

    nota

    Todas las solicitudes PUT requieren un tipo de suma de comprobación de objeto completo.

  • Sumas de comprobación compuestas: una suma de comprobación compuesta se calcula en función de las sumas de comprobación individuales de cada parte en una carga multiparte. En lugar de calcular una suma de comprobación basada en todo el contenido de los datos, este enfoque agrega las sumas de comprobación a nivel de parte (desde la primera parte hasta la última) para producir una sola suma de comprobación combinada para el objeto completo.

    nota

    Cuando un objeto se carga como carga multiparte, la etiqueta de entidad (ETag) del objeto no es un resumen MD5 de todo el objeto. En su lugar, Amazon S3 calcula el resumen MD5 de cada parte individual a medida que se carga. Los resúmenes MD5 se utilizan para determinar la ETag del objeto final. Amazon S3 concatena los bytes de los resúmenes MD5 y, a continuación, calcula el resumen MD5 de estos valores concatenados. Durante el paso final de creación de la ETag, Amazon S3 agrega un guion con el número total de partes al final.

Amazon S3 admite los siguientes tipos de algoritmos de suma de comprobación compuesta y de objeto completo:

  • CRC-64/NVME (CRC64NVME): solo admite el tipo de algoritmo de objeto completo.

  • CRC-32 (CRC32): admite algoritmos compuestos y de objeto completo.

  • CRC-32C (CRC32C): admite algoritmos compuestos y de objeto completo.

  • SHA-1 (SHA1): admite algoritmos compuestos y de objeto completo.

  • SHA-256 (SHA256): admite algoritmos compuestos y de objeto completo.

Cargas de partes individuales

Las sumas de comprobación de los objetos que se cargan en una sola parte (mediante PutObject) se tratan como sumas de comprobación de objeto completo. Cuando carga un objeto en la consola de Amazon S3, puede elegir el algoritmo de suma de comprobación que desea que utilice S3 y también (opcionalmente) proporcionar un valor precalculado. Amazon S3 valida esta suma de comprobación antes de almacenar el objeto y el valor de suma de comprobación. Puede verificar la integridad de los datos de un objeto cuando solicita el valor de la suma de comprobación durante las descargas de objetos.

Cargas multiparte

Cuando carga el objeto en varias partes mediante la API MultipartUpload, puede especificar el algoritmo de suma de comprobación que desea que utilice Amazon S3 y el tipo de suma de comprobación (objeto completo o compuesto).

La siguiente tabla indica qué tipo de algoritmo de suma de comprobación es compatible con cada algoritmo de suma de comprobación en una carga multiparte:

Algoritmo de suma de comprobación Objeto completo Compuesto
CRC-64/NVME (CRC64NVME) No
CRC-32 (CRC32)
CRC-32C (CRC32C)
SHA-1 (SHA1)
SHA-256 (SHA256)

Uso de sumas de comprobación de objeto completo para la carga multiparte

Al crear o realizar una carga multiparte, puede utilizar sumas de comprobación de objeto completo para la validación en la carga. Esto significa que puede proporcionar el algoritmo de suma de comprobación para la API MultipartUpload, lo que simplifica las herramientas de validación de integridad porque ya no necesita realizar un seguimiento de los límites de las partes para los objetos cargados. Puede proporcionar la suma de comprobación de todo el objeto en la solicitud CompleteMultipartUpload, junto con el tamaño del objeto.

Cuando proporciona una suma de comprobación de objeto completa durante una carga multiparte, el SDK de AWS pasa la suma de comprobación a Amazon S3 y S3 valida la integridad del objeto en el servidor y lo compara con el valor recibido. A continuación, Amazon S3 almacena el objeto si los valores coinciden. Si los dos valores no coinciden, S3 no realiza la solicitud y genera el error BadDigest. La suma de comprobación del objeto también se almacena en los metadatos del objeto que utilizará más adelante para validar la integridad de los datos de un objeto.

En las sumas de comprobación de objeto completo, puede utilizar algoritmos de suma de comprobación CRC-64/NVME (CRC64NVME), CRC-32 (CRC32) o CRC-32C (CRC32C) en S3. Las sumas de comprobación de objeto completo en cargas multiparte solo están disponibles para sumas de comprobación basadas en CRC porque pueden linealizarse en una suma de comprobación de objeto completo. Esta linealización permite a Amazon S3 paralelizar las solicitudes para mejorar el rendimiento. En concreto, S3 puede calcular la suma de comprobación de todo el objeto a partir de las sumas de comprobación a nivel de parte. Este tipo de validación no está disponible para otros algoritmos, como SHA y MD5. Debido a que S3 tiene protecciones de integridad predeterminadas, si los objetos se cargan sin una suma de comprobación, S3 asocia automáticamente el algoritmo recomendado de suma de comprobación CRC-64/NVME (CRC64NVME) de objeto completo.

nota

Para iniciar la carga multiparte, puede especificar el algoritmo de suma de comprobación y el tipo de suma de comprobación de objeto completo. Tras especificar el algoritmo de suma de comprobación y el tipo de suma de comprobación de objeto completo, puede proporcionar el valor de la suma de comprobación de objeto completo para la carga multiparte.

Uso de sumas de comprobación a nivel de parte para carga multiparte

Cuando los objetos se cargan en Amazon S3, se pueden cargar como un solo objeto o cargarse en partes mediante el proceso de carga multiparte. Puede elegir un tipo de suma de comprobación para la carga multiparte. Para las sumas de comprobación a nivel de parte (o sumas de comprobación compuestas) de carga multiparte, Amazon S3 calcula la suma de comprobación para cada parte individual mediante el algoritmo de suma de comprobación especificado. Puede utilizar UploadPart para proporcionar los valores de suma de comprobación de cada parte. Si el objeto que intenta cargar en la consola de Amazon S3 se establece en el algoritmo de suma de comprobación CRC-64/NVME (CRC64NVME) y supera los 16 MB, se designa automáticamente como suma de comprobación de objeto completo.

Amazon S3 utiliza los valores de suma de comprobación almacenados a nivel de parte para confirmar que cada parte se carga correctamente. Cuando se proporciona la suma de comprobación de cada parte (para todo el objeto), S3 utiliza los valores de suma de comprobación almacenados de cada parte para calcular internamente la suma de comprobación de objeto completo, comparándola con el valor de suma de comprobación proporcionado. Esto minimiza los costos de computación, ya que S3 puede calcular una suma de comprobación de todo el objeto mediante la suma de comprobación de las partes. Para obtener más información acerca de las cargas multiparte, consulte Carga y copia de objetos con la carga multiparte en Amazon S3 y Uso de sumas de comprobación de objeto completo para la carga multiparte.

Cuando el objeto se haya cargado por completo, puede utilizar la suma de comprobación final calculada para verificar la integridad de datos del objeto.

Al cargar una parte de la carga multiparte, tenga en cuenta lo siguiente:

  • Para recuperar información sobre el objeto, incluida la cantidad de partes que componen todo el objeto, puede utilizar la operación GetObjectAttributes. Con sumas de comprobación adicionales, también puede recuperar información de cada parte individual que incluye el valor de suma de comprobación de la parte.

  • En el caso de cargas completadas, puede obtener la suma de comprobación de una parte individual mediante la operación GetObject o HeadObject y especificar un número de parte o rango de bytes que se ajuste a una sola parte. Si quiere recuperar los valores de la suma de comprobación de partes individuales de las cargas multiparte que aún están en progreso, puede utilizar ListParts.

  • Debido a la forma en que Amazon S3 calcula la suma de comprobación de objetos multiparte, es posible que el valor de la suma de comprobación del objeto cambie si lo copia. Si utiliza un SDK o la API de REST y llama a CopyObject, Amazon S3 copia cualquier objeto hasta el tamaño límite de la operación de la API CopyObject. Amazon S3 realiza esta copia como una sola acción, independientemente de si el objeto se ha cargado en una sola solicitud o como parte de una carga multiparte. Con un comando de copia, la suma de comprobación del objeto es una suma de comprobación directa de todo el objeto. Si el objeto se cargó originalmente mediante una carga multiparte, el valor de la suma de comprobación cambia aunque los datos no lo hagan.

  • Los objetos que superen los límites de tamaño de la operación de la API CopyObject deben utilizar comandos de copia de carga multiparte.

  • Cuando realiza algunas operaciones con la AWS Management Console, Amazon S3 utiliza una carga multiparte si el objeto tiene un tamaño superior a 16 MB.

Operaciones de suma de comprobación

Después de cargar objetos, puede obtener el valor de la suma de comprobación y compararlo con un valor de suma de comprobación precalculado o almacenado previamente del mismo tipo de algoritmo. En los siguientes ejemplos se muestran las operaciones o métodos de suma de comprobación que puede utilizar para verificar la integridad de los datos.

Para obtener más información sobre el uso de la consola y la especificación de los algoritmos de suma de comprobación que se utilizan al cargar objetos, consulte Carga de objetos y el Tutorial: Comprobación de la integridad de los datos en Amazon S3 con sumas de comprobación adicionales.

En el siguiente ejemplo, se muestra cómo se pueden utilizar los SDK de AWS para cargar un archivo grande con carga multiparte, descargar un archivo grande y validar un archivo de carga multiparte, todo mediante SHA-256 para la validación de archivos.

Java
ejemplo Ejemplo: carga, descarga y verificación de un archivo grande con SHA-256

Para obtener instrucciones sobre cómo crear y probar una muestra funcional, consulte Introducción en la Guía para desarrolladores de AWS SDK para 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(); } } }

Puede enviar solicitudes REST para cargar un objeto con un valor de suma de comprobación para verificar la integridad de los datos con PutObject. También puede recuperar el valor de suma de comprobación de los objetos con GetObject o HeadObject.

Envíe una solicitud PUT para cargar un objeto de hasta 5 GB en una única operación. Para obtener más información, consulte PutObject en la Referencia de comandos de AWS CLI. También puede utilizar get-object y head-object para recuperar la suma de comprobación de un objeto ya cargado para verificar la integridad de los datos.

Para ver más información, consulte Amazon S3 CLI FAQ en la Guía del usuario de la AWS Command Line Interface.

Uso de Content-MD5 al cargar objetos

Otra forma de verificar la integridad del objeto después de cargarlo es proporcionar un resumen MD5 del objeto al cargarlo. Si calcula el resumen MD5 de su objeto, puede proporcionar el resumen con el comando PUT mediante el encabezado Content-MD5.

Tras cargar el objeto, Amazon S3 calcula el resumen MD5 del objeto y lo compara con el valor que proporcionó. La solicitud se realiza correctamente solo si los dos resúmenes coinciden.

No es necesario suministrar un resumen MD5, pero puede usarlo para verificar la integridad del objeto como parte del proceso de carga.

Uso de Content-MD5 y ETag para verificar los objetos cargados

La etiqueta de entidad (ETag) de un objeto representa una versión específica de ese objeto. Tenga en cuenta que la ETag solo refleja los cambios en el contenido de un objeto, no en los metadatos. Si solo cambian los metadatos de un objeto, la ETag sigue siendo la misma.

Según el objeto, la ETag del objeto puede ser un resumen MD5 de los datos del objeto:

  • Si un objeto se ha creado con la operación PutObject, PostObject o CopyObject, o a través de AWS Management Console, y también tiene texto sin formato o está cifrado mediante cifrado del lado del servidor con claves administradas de Amazon S3 (SSE-S3), ese objeto tiene una ETag que es un resumen MD5 de sus datos de objeto.

  • Si un objeto se ha creado con la operación PutObject, PostObject o CopyObject, o a través de AWS Management Console, y está cifrado mediante cifrado del lado del servidor con claves proporcionadas por el cliente (SSE-C) o mediante cifrado del lado del servidor con AWS Key Management Service (AWS KMS) (SSE-KMS), ese objeto tiene una ETag que no es un resumen MD5 de sus datos de objeto.

  • Si un objeto se crea mediante el proceso de carga multiparte o la operación UploadPartCopy, la ETag del objeto no es un resumen MD5, independientemente del método de cifrado. Si un objeto tiene más de 16 MB, la AWS Management Console carga o copia ese objeto como carga multiparte y, por lo tanto, la ETag no es un resumen MD5.

Para objetos en los que la ETag es el resumen Content-MD5 del objeto, puede comparar el valor de ETag del objeto con un resumen Content-MD5 calculado o almacenado previamente.

Uso de sumas de comprobación finales

Al cargar objetos en Amazon S3, puede proporcionar una suma de comprobación calculada previamente para el objeto o utilizar un SDK de AWS para crear automáticamente sumas de comprobación finales para cargas fragmentadas en su nombre. Si utiliza una suma de comprobación final, Amazon S3 genera automáticamente la suma de comprobación mediante el algoritmo especificado para validar la integridad del objeto en cargas fragmentadas, cuando carga un objeto.

Para crear una suma de comprobación final cuando utilice un SDK de AWS, rellene el parámetro ChecksumAlgorithm con su algoritmo preferido. El SDK utiliza ese algoritmo para calcular la suma de comprobación del objeto (o partes de objeto) y lo anexa automáticamente al final de la solicitud de carga fragmentada. Este comportamiento le ahorra tiempo porque Amazon S3 realiza la verificación y la carga de sus datos en un solo pase.

importante

Si utiliza S3 Object Lambda, todas las solicitudes a S3 Object Lambda se firman mediante s3-object-lambda en lugar de s3. Este comportamiento afecta a la firma de los valores de suma de comprobación final. Para obtener más información acerca de S3 Object Lambda, consulte Transformación de objetos con Lambda para objetos S3.

Encabezados de suma de comprobación final

Para realizar una solicitud de codificación de contenido fragmentado, Amazon S3 requiere que los servidores cliente incluyan varios encabezados para analizar correctamente la solicitud. Los servidores cliente deben incluir los siguientes encabezados:

  • x-amz-decoded-content-length: este encabezado indica el tamaño del texto sin formato de los datos reales que se están cargando en Amazon S3 con la solicitud.

  • x-amz-content-sha256: este encabezado indica el tipo de carga fragmentada que se incluye en la solicitud. Para cargas fragmentadas con sumas de comprobación finales, el valor del encabezado es STREAMING-UNSIGNED-PAYLOAD-TRAILER para solicitudes que no utilizan firma de carga útil y STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER para solicitudes que utilizan la firma de carga útil de SigV4. (Para obtener más información sobre cómo implementar cargas firmadas, consulte Cálculos de firma para el encabezado de autorización: transferencia de una carga útil en múltiples fragmentos).

  • x-amz-trailer: este encabezado indica el nombre del encabezado final de la solicitud. Si existen sumas de comprobación finales (donde los SDK de AWS adjuntan sumas de comprobación a los cuerpos de solicitud codificados), el valor del encabezado x-amz-trailer incluye el prefijo x-amz-checksum- y termina con el nombre del algoritmo. Actualmente, se admiten los siguientes valores de x-amz-trailer:

    • x-amz-checksum-crc32

    • x-amz-checksum-crc32c

    • x-amz-checksum-crc64nvme

    • x-amz-checksum-sha1

    • x-amz-checksum-sha256

nota

También puede incluir el encabezado Content-Encoding, con el valor fragmentado, en la solicitud. Aunque este encabezado no es obligatorio, incluirlo puede minimizar los problemas de proxy HTTP al transmitir datos codificados. Si existe otro encabezado Content-Encoding (como gzip) en la solicitud, el encabezado Content-Encoding incluye el valor fragmentado en una lista de codificaciones separadas por comas. Por ejemplo, Content-Encoding: aws-chunked, gzip.

Partes fragmentadas

Cuando carga un objeto en Amazon S3 mediante codificación fragmentada, la solicitud de carga incluye los siguientes tipos de fragmentos (formateados en el orden indicado):

  • Fragmentos de cuerpo de objeto: puede haber uno, varios o ningún fragmento de cuerpo asociado a una solicitud de carga fragmentada.

  • Fragmentos de finalización: puede haber uno, varios o ningún fragmento de cuerpo asociado a una solicitud de carga fragmentada.

  • Fragmentos finales: la suma de comprobación final aparece después del fragmento de finalización. Solo se permite un fragmento final.

nota

Cada carga fragmentada debe terminar con un CRLF final (como \r\n) para indicar el final de la solicitud.

Para obtener ejemplos de formato fragmentado, consulte Ejemplos: cargas fragmentadas con sumas de comprobación finales.

Fragmentos de cuerpo de objeto

Los fragmentos de cuerpo de objeto son los fragmentos que contienen los datos reales del objeto que se están cargando en S3. Estos fragmentos tienen restricciones de tamaño y formato coherentes.

Tamaño de fragmento de cuerpo de objeto

Estos fragmentos deben contener al menos 8192 bytes (u 8 KiB) de datos de objeto, excepto el fragmento de cuerpo final, que puede ser más pequeño. No hay un tamaño máximo explícito para los fragmentos, pero puede esperar que todos los fragmentos sean más pequeños que el tamaño máximo de carga de 5 GB. Los tamaños de fragmento pueden variar de un fragmento a otro en función de cómo haya implementado el cliente el servidor.

Formato de fragmento de cuerpo de objeto

Los fragmentos de cuerpo de objeto comienzan con la codificación hexadecimal del número de bytes en el fragmento de cuerpo de objeto, seguido de un CRLF (retorno de carro y avance de línea), los bytes de objeto para ese fragmento y otro CRLF.

Por ejemplo:

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

No obstante, cuando el fragmento está firmado, el fragmento de cuerpo de objeto sigue un formato diferente, en el que la firma se adjunta al tamaño de fragmento con un delimitador de punto y coma. Por ejemplo:

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

Para obtener más información sobre la firma de fragmentos, consulte Cálculos de firma para el encabezado Authorization: transferencia de una carga útil en múltiples fragmentos (AWS Signature Version 4). Para obtener más información sobre el formato de fragmento, consulte Chunked transfer encoding en el sitio web del Editor de RFC.

Fragmentos de finalización

Los fragmentos de finalización deben ser el fragmento de cuerpo de objeto final de cada carga fragmentada. El formato de un fragmento de finalización es similar al de un fragmento de cuerpo, pero siempre contiene cero bytes de datos de objeto. (Los cero bytes de datos de objeto indican que todos los datos se han cargado). Las cargas fragmentadas deben incluir un fragmento de finalización como fragmento de cuerpo de objeto final, siguiendo un formato como este:

0\r\n

No obstante, si la solicitud de codificación de contenido utiliza la firma de carga útil, sigue este formato en su lugar:

0;chunk-signature\r\n

Fragmentos finales

Los fragmentos finales contienen la suma de comprobación calculada para todas las solicitudes de carga de S3. Los fragmentos finales incluyen dos campos: un campo de nombre de encabezado y un campo de valor de encabezado. El campo de nombre de encabezado para una solicitud de carga debe coincidir con el valor pasado en el encabezado de solicitud x-amz-trailer. Por ejemplo, si una solicitud contiene x-amz-trailer: x-amz-checksum-crc32 y el fragmento final tiene el nombre de encabezado x-amz-checksum-sha1, se produce un error en la solicitud. El campo de valor en el fragmento final incluye una codificación en base64 del valor de suma de comprobación big-endian para ese objeto. (El orden big-endian almacena el byte de datos más significativo en la dirección de memoria más baja y el byte menos significativo en la dirección de memoria más grande). El algoritmo utilizado para calcular esta suma de comprobación es el mismo que el sufijo para el nombre de encabezado (por ejemplo, crc32).

Formato de fragmento final

Los fragmentos finales utilizan el siguiente formato para solicitudes de carga útil sin firmar:

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

Para solicitudes con cargas útiles firmadas con SigV4, el fragmento final incluye una firma final después del fragmento final.

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

También puede agregar el CRLF directamente al final del valor de la suma de comprobación en base64. Por ejemplo:

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

Ejemplos: cargas fragmentadas con sumas de comprobación finales

Amazon S3 admite cargas fragmentadas que utilizan codificación de contenido de aws-chunked para solicitudes PutObject y UploadPart con sumas de comprobación finales.

ejemplo 1: solicitud PutObject fragmentada sin firmar con una suma de comprobación CRC-32 final

A continuación, se muestra un ejemplo de una solicitud PutObject fragmentada con una suma de comprobación CRC-32 final. En este ejemplo, el cliente carga un objeto de 17 KB en tres fragmentos sin firmar y adjunta un fragmento de suma de comprobación CRC-32 final mediante el encabezado 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

Aquí tiene una respuesta de ejemplo:

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

El uso del salto de línea \n al final del valor de la suma de comprobación puede variar de un cliente a otro.

ejemplo 2: solicitud PutObject fragmentada firmada por SigV4 con una suma de comprobación CRC-32 (CRC32) final

A continuación, se muestra un ejemplo de una solicitud PutObject fragmentada con una suma de comprobación CRC-32 final. Esta solicitud utiliza la firma de carga útil de SigV4. En este ejemplo, el cliente carga un objeto de 17 KB en tres fragmentos firmados. Además de los fragmentos object body, también se firman completion chunk y 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

Aquí tiene una respuesta de ejemplo:

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