Creación de una solicitud de API de AWS firmada - AWS Identity and Access Management

Creación de una solicitud de API de AWS firmada

importante

Si usa un SDK de AWS (consulte Código de muestra y bibliotecas) o la herramienta de línea de comandos (CLI) de AWS para enviar solicitudes de API a AWS, puede omitir esta sección porque los clientes del SDK y la CLI autentican sus solicitudes mediante las claves de acceso que usted proporciona. A menos que tenga una razón específica para no hacerlo, le recomendamos que utilice siempre un SDK o la CLI.

En las regiones en las que se admiten varias versiones de firma, las solicitudes de firma manual significan que debe especificar qué versión de firma se utiliza. Cuando envía solicitudes a puntos de acceso de varias regiones, los SDK y la CLI cambian de forma automática a Signature Version 4A sin configuración adicional.

A continuación, se muestra el proceso para crear una solicitud firmada. A fin de calcular una firma, primero necesita una cadena para firmar. Luego, se calcula un hash HMAC-SHA256 de la cadena que se va a firmar mediante una clave de firma. En el siguiente diagrama se ilustra el proceso, incluidos los distintos componentes de la cadena que se crea para la firma.


                Una imagen de las partes de una solicitud canónica, cadena para firmar, clave de firma y firma.

En la siguiente tabla, se describen las funciones que se muestran en el diagrama. Debe implementar código para estas funciones. Para obtener más información, consulte ejemplos de código en los SDK de AWS.

Función Descripción

Lowercase()

Convierta la cadena de caracteres en minúsculas.

Hex()

Codificación en minúsculas en base 16.

SHA256Hash()

Función de hash criptográfico del algoritmo de hash seguro (SHA).

HMAC-SHA256()

Calcula el HMAC mediante el algoritmo SHA256 con la clave de firma proporcionada. Esta es la firma final.

Trim()

Elimine cualquier espacio en blanco inicial o final.

UriEncode()

El URI codifica cada byte. UriEncode() debe aplicar las siguientes reglas:

  • El URI codifica todos los bytes excepto los caracteres no reservados: “A”-“Z”, “a”-“z”, “0”-“9”, “-”, “.”, “_” y “~”.

  • El carácter de espacio es un carácter reservado y debe codificarse como “%20” (y no como “+”).

  • Cada byte codificado en URI se encuentra formado por un “%” y el valor hexadecimal de dos dígitos del byte.

  • Las letras del valor hexadecimal deben estar en mayúsculas, por ejemplo, “%1A”.

  • Codifique el carácter de barra diagonal, “/”, en todas partes excepto en el nombre de la clave del objeto. Por ejemplo, si el nombre de la clave del objeto es photos/Jan/sample.jpg, la barra diagonal del nombre de la clave no se encuentra codificada.

importante

Es posible que las funciones estándar de UriEncode que proporciona su plataforma de desarrollo no funcionen debido a las diferencias en la implementación y a la ambigüedad relacionada en las RFC subyacentes. Le recomendamos que escriba su propia función UriEncode personalizada para asegurarse de que la codificación funcione.

Para ver un ejemplo de una función UriEncode en Java, consulte Utilidades de Java en el sitio web de GitHub.

nota

Al firmar sus solicitudes, puede utilizar cualquiera de las siguientes opciones: AWS Signature Version 4 o AWS Signature Version 4A. La diferencia clave entre las dos se determina por la forma en que se calcula la firma. Con AWS Signature Version 4A, la firma no incluye información específica de la región y se calcula mediante el algoritmo AWS4-ECDSA-P256-SHA256.

Credenciales de seguridad temporales

En lugar de utilizar credenciales de larga duración para firmar una solicitud, puede utilizar las credenciales de seguridad temporales proporcionadas por AWS Security Token Service (AWS STS).

Cuando utilice credenciales de seguridad temporales, debe agregar X-Amz-Security-Token al encabezado de autorización o a la cadena de consulta para contener el token de sesión. Algunos servicios requieren que agregue X-Amz-Security-Token a la solicitud canónica. Otros servicios requieren que solo agregue X-Amz-Security-Token al final, después de calcular la firma. Consulte la documentación de cada Servicio de AWS para obtener más detalles.

Resumen de pasos de firma

Paso 1: creación de una solicitud canónica

Organice el contenido de la solicitud (host, acción, encabezados, etc.) en un formato canónico estándar. La solicitud canónica es uno de los datos de entrada utilizados con el fin de crear una cadena para firmar. Para obtener más información, consulte Elementos de una firma de solicitud a la API de AWS.

Paso 2: creación de un hash de la solicitud canónica

Genere una clave de firma al llevar a cabo una sucesión de operaciones hash con clave (operaciones HMAC) en la fecha de la solicitud, la región y el servicio, con su clave de acceso secreta de AWS como clave de la operación hash inicial.

Paso 3: Creación de una cadena para firmar

Cree una cadena para firmar con la solicitud canónica e información adicional, como el algoritmo, la fecha de la solicitud, el ámbito de credenciales y el resumen (hash) de la solicitud canónica.

Paso 4: cálculo de la firma

Una vez generada la clave de firma, se calcula la firma llevando a cabo una operación hash con clave en la cadena para firmar. Utilice la clave de firma generada como clave hash para esta operación.

Paso 5: adición de la firma a la solicitud

Después de calcular la firma, añádasela a un encabezado HTTP o a la cadena de consulta de la solicitud.

Paso 1: creación de una solicitud canónica

Crea una solicitud canónica al concatenar las siguientes cadenas, separadas por caracteres de nueva línea. Esto ayuda a garantizar que la firma que calcula y la firma que calcula AWS puedan coincidir.

<HTTPMethod>\n <CanonicalURI>\n <CanonicalQueryString>\n <CanonicalHeaders>\n <SignedHeaders>\n <HashedPayload>
  • HTTPMethod: el método HTTP, como GET, PUT, HEAD y DELETE.

  • CanonicalUri: la versión codificada en URI del URI del componente de ruta absoluta, que comienza con la “/” que sigue al nombre de dominio y continúa hasta el final de la cadena o del signo de interrogación (“?”) si tiene parámetros de cadena de consulta. Si la ruta absoluta está vacía, utilice un carácter de barra diagonal (/). El URI del siguiente ejemplo, /examplebucket/myphoto.jpg, es la ruta absoluta y no se codifica la “/” en la ruta absoluta:

    http://s3.amazonaws.com/examplebucket/myphoto.jpg
  • CanonicalQueryString: los parámetros de la cadena de consulta codificados en URI. Codifique en URI cada nombre y valores de forma individual. También debe ordenar los parámetros de la cadena de consulta canónica alfabéticamente por nombre de clave. La clasificación se produce después de la codificación. La cadena de consulta del siguiente ejemplo de URI es:

    http://s3.amazonaws.com/examplebucket?prefix=somePrefix&marker=someMarker&max-keys=2

    La cadena de consulta canónica es la siguiente (se agregan saltos de línea a este ejemplo para facilitar la lectura):

    UriEncode("marker")+"="+UriEncode("someMarker")+"&"+ UriEncode("max-keys")+"="+UriEncode("20") + "&" + UriEncode("prefix")+"="+UriEncode("somePrefix")

    Cuando una solicitud se dirige a un subrecurso, el valor del parámetro de consulta correspondiente será una cadena vacía (“”). Por ejemplo, el siguiente URI identifica el subrecurso ACL en el bucket examplebucket:

    http://s3.amazonaws.com/examplebucket?acl

    En este caso, la cadena CanonicalQueryString es la siguiente:

    UriEncode("acl") + "=" + ""

    Si el URI no incluye un “?”, no hay ninguna cadena de consulta en la solicitud y establece la cadena de consulta canónica en una cadena vacía (“”). Aún tendrá que incluir “\n”.

  • CanonicalHeaders: una lista de los encabezados de las solicitudes con sus valores. Los pares individuales de nombre y valor del encabezado se encuentran separados por el carácter de nueva línea (“\n”). El siguiente es un ejemplo de un encabezado canónico:

    Lowercase(<HeaderName1>)+":"+Trim(<value>)+"\n" Lowercase(<HeaderName2>)+":"+Trim(<value>)+"\n" ... Lowercase(<HeaderNameN>)+":"+Trim(<value>)+"\n"

    La lista CanonicalHeaders debe incluir lo siguiente:

    • Encabezado de host HTTP.

    • Si el encabezado Content-Type se encuentra en la solicitud, debe agregarlo a la lista CanonicalHeaders.

    • También debe agregar cualquier encabezado x-amz-* que planea incluir en su solicitud. Por ejemplo, si utiliza credenciales de seguridad temporales, debe incluir x-amz-security-token en su solicitud. Debe agregar este encabezado a la lista de CanonicalHeaders.

    nota

    El encabezado x-amz-content-sha256 es obligatorio para las solicitudes de AWS de Amazon S3. Proporciona un hash de la carga de solicitud. Si no hay ninguna carga, debe proporcionar el hash de una cadena vacía.

    Cada nombre de encabezado debe:

    • tener caracteres en minúsculas;

    • aparecer en orden alfabético;

    • ir seguido de dos puntos (:).

    En el caso de los valores, debe:

    • recortar los espacios iniciales o finales;

    • convertir espacios secuenciales en un solo espacio;

    • separar los valores de un encabezado con varios valores mediante comas.

    • Debe incluir el encabezado de host (HTTP/1.1) o el encabezado :authority (HTTP/2) y cualquier encabezado x-amz-* de la firma. Si lo desea, puede incluir otros encabezados estándar en la firma, como content-type.

    Las funciones Lowercase() y Trim() que se utilizan en este ejemplo se describen en la sección anterior.

    La siguiente es una cadena de CanonicalHeaders de ejemplo. Los nombres de encabezado se encuentran en minúsculas y ordenados.

    host:s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130708T220855Z

    nota

    Para calcular una firma de autorización, solo se requieren el host y cualquier encabezado x-amz-*; sin embargo, a fin de evitar la manipulación de datos, debería considerar la posibilidad de incluir todos los encabezados en el cálculo de la firma.

  • SignedHeaders: una lista ordenada alfabéticamente y separada por punto y coma de nombres de encabezados de solicitudes en minúsculas. Los encabezados de las solicitudes de la lista son los mismos que incluyó en la cadena de CanonicalHeaders. Por ejemplo, para el caso anterior, el valor de SignedHeaders sería el siguiente:

    host;x-amz-content-sha256;x-amz-date
  • HashedPayload: una cadena creada con la carga del cuerpo de la solicitud HTTP como entrada para una función de hash. Esta cadena utiliza caracteres hexadecimales en minúscula.

    Hex(SHA256Hash(<payload>)

    Si no hay ninguna carga en la solicitud, se calcula un hash de la cadena vacía de la siguiente manera:

    Hex(SHA256Hash(""))

    El hash devuelve los siguientes valores:

    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

    Por ejemplo, cuando carga un objeto mediante una solicitud PUT, proporciona los datos del objeto en el cuerpo. Al recuperar un objeto mediante una solicitud GET, se calcula el hash de la cadena vacía.

Paso 2: creación de un hash de la solicitud canónica

Cree un hash (resumen) de la solicitud canónica con el mismo algoritmo que utilizó para crear el hash de la carga. El hash de la solicitud canónica es una cadena de caracteres hexadecimales en minúsculas.

Paso 3: Creación de una cadena para firmar

Cree una cadena al concatenar las siguientes cadenas, separadas por caracteres de nueva línea. No termine esta cadena con un carácter de nueva línea.

Algorithm \n RequestDateTime \n CredentialScope \n HashedCanonicalRequest
  • Algorithm: el algoritmo utilizado para crear el hash de la solicitud canónica. Para SHA-256, el algoritmo es AWS4-HMAC-SHA256.

  • RequestDateTime: la fecha y la hora utilizadas en el alcance de la credencial. Este valor es la hora UTC actual en formato ISO 8601 (por ejemplo, 20130524T000000Z).

  • CredentialScope: el alcance de la credencial. Esto restringe la firma resultante a la región y el servicio especificados. La cadena tiene el siguiente formato:YYYYMMDD/region/service/aws4_request.

  • HashedCanonicalRequest: el hash de la solicitud canónica. Este valor se calcula en el paso 2.

La siguiente es una cadena de ejemplo para firmar.

"AWS4-HMAC-SHA256" + "\n" + timeStampISO8601Format + "\n" + <Scope> + "\n" + Hex(SHA256Hash(<CanonicalRequest>))

Paso 4: cálculo de la firma

En AWS Signature Version 4, en lugar de utilizar sus claves de acceso de AWS para firmar una solicitud, crea una clave de firma que se limita a una región y un servicio específicos como información de autenticación que agregará a su solicitud.

DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>") DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>") SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")

Para obtener una lista de las cadenas de región, consulte Puntos de conexión regionales en la Referencia general de AWS.

Para cada paso, llame a la función de hash con la clave y los datos necesarios. El resultado de cada llamada a la función de hash se convierte en la entrada de la siguiente llamada a la función de hash.

Datos de ingreso obligatorios
  • Una cadena Key, la cual contiene su clave de acceso secreta

  • Una cadena Date, la cual contiene la fecha utilizada en el alcance de la credencial con el formato AAAAMMDD

  • Una cadena Region, la cual contiene el código de región (por ejemplo, us-east-1)

  • Una cadena Service, la cual contiene el código de servicio (por ejemplo, ec2)

  • La cadena para firmar que creó en el paso anterior.

Para calcular la firma
  1. Concatene “AWS4” y la clave de acceso secreta. Llame a la función de hash con la cadena concatenada como clave y la cadena de fecha como datos.

    kDate = hash("AWS4" + Key, Date)
  2. Llame a la función de hash con el resultado de la llamada anterior como clave y la cadena de región como datos.

    kRegion = hash(kDate, Region)
  3. Llame a la función de hash con el resultado de la llamada anterior como clave y la cadena de servicio como datos.

    kService = hash(kRegion, Service)
  4. Llame a la función de hash con el resultado de la llamada anterior como clave y “aws4_request” como datos.

    kSigning = hash(kService, "aws4_request")
  5. Llame a la función de hash con el resultado de la llamada anterior como clave y la cadena para firmar como datos. El resultado es la firma como valor binario.

    signature = hash(kSigning, string-to-sign)
  6. Convierta la firma de representación binaria a hexadecimal, en caracteres en minúsculas.

Paso 5: adición de la firma a la solicitud

ejemplo Ejemplo: encabezado de autorización

En el ejemplo siguiente se muestra un encabezado Authorization para la acción DescribeInstances. Para facilitar la lectura, este ejemplo está formateado con saltos de línea. En su código, debe ser una cadena continua. No hay ninguna coma entre el algoritmo y Credential. Sin embargo, los demás elementos deben ir separados por comas.

Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=calculated-signature
ejemplo Ejemplo: solicitud con parámetros de autenticación en la cadena de consulta

En el siguiente ejemplo, se muestra una consulta para la acción DescribeInstances que incluye la información de autenticación. Para facilitar la lectura, este ejemplo está formateado con saltos de línea y no está codificado en URL. En el código, la cadena de consulta debe ser una cadena continua codificada en URL.

https://ec2.amazonaws.com/? Action=DescribeInstances& Version=2016-11-15& X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request& X-Amz-Date=20220830T123600Z& X-Amz-SignedHeaders=host;x-amz-date& X-Amz-Signature=calculated-signature

Código fuente en los SDK de AWS

Los SDK de AWS incluyen código fuente en GitHub para firmar las solicitudes de la API de AWS. Para obtener ejemplos de código, consulte Proyectos de ejemplo en AWS repositorio de muestras