Firmar y autenticar las solicitudes REST
Temas
- Uso de credenciales de seguridad temporales
- El encabezado de autenticación
- Solicitar canonicalización para firmas
- Crear elemento CanonicalizedResource
- Crear el elemento CanonicalizedAmzHeaders
- Elementos StringToString de los encabezados HTTP: posicionales frente a denominados
- Requisitos de marca temporal
- Ejemplos de autenticación
- Problemas de firma con solicitudes REST
- Alternativa de autenticación por cadena de consulta de solicitudes
nota
En este tema se explica la autenticación de solicitudes mediante el uso de Signature Versión 2. Amazon S3 ya es compatible con Signature Version 4. Esta última versión de Signature puede utilizarse en todas las regiones, y las nuevas regiones solo permitirán el uso de Signature versión 4 tras el 30 de enero de 2014. Para obtener más información, vaya a Autenticación de solicitudes (AWS Signature Version 4) en la Referencia de la API de Amazon Simple Storage Service.
La autenticación es el proceso que consiste en demostrar la identidad del usuario a un sistema. La identidad es un factor importante en las decisiones sobre el control de accesos en Amazon S3. Las solicitudes se admiten o se rechazan, en parte, en función de la identidad del solicitante. Por ejemplo, el derecho a crear buckets se reserva a los desarrolladores registrados, y el derecho a crear objetos en un bucket (de manera predeterminada) se reserva al propietario del bucket en cuestión. Como desarrollador, estará realizando solicitudes que invoquen estos privilegios, por lo que tendrá que demostrar su identidad al sistema autenticando sus solicitudes. En esta sección le demostramos cómo.
nota
El contenido de esta sección no se aplica al método HTTP POST. Para obtener más información, consulte Cargas basadas en el navegador con POST (AWS Signature Version 2).
La API de REST de Amazon S3 usa un esquema HTTP personalizado basado en un HMAC (Hash Message Authentication Code) con clave para la autenticación. Para autenticar una solicitud, primero ha de concatenar los elementos seleccionados en la solicitud para formar una cadena. A continuación, utilice su clave de acceso secreta de AWS para calcular el HMAC de esa cadena. Este proceso se denomina informalmente "firmar la solicitud", y al resultado del algoritmo HMAC se le llama la firma, ya que simula las propiedades de seguridad de una firma real. Por último, tendrá que agregar esta firma como parámetro de la solicitud empleando la sintaxis descrita en esta sección.
Cuando el sistema recibe una solicitud autenticada, toma la clave de acceso secreta de AWS que usted afirma tener y la utiliza del mismo modo para computar una firma para el mensaje recibido. A continuación, compara la firma calculada con la firma que presenta el solicitante. Si ambas firmas coinciden, el sistema concluye que el solicitante debe de tener acceso a la clave de acceso secreta de AWS y, por lo tanto, actúa con la autoridad de la solicitud principal para la que se emitió la clave. Si las dos firmas no coinciden, la solicitud se abandona y el sistema responde con un mensaje de error.
ejemplo Solicitud REST autenticada de Amazon S3
GET /photos/puppy.jpg HTTP/1.1 Host: awsexamplebucket1.us-west-1.s3.amazonaws.com Date: Tue, 27 Mar 2007 19:36:42 +0000
Authorization: AWS AKIAIOSFODNN7EXAMPLE: qgk2+6Sv9/oM7G3qLEjTH1a1l1g=
Uso de credenciales de seguridad temporales
Si firma su solicitud con credenciales de seguridad temporales (consulte Realizar solicitudes), deberá incluid el token de seguridad correspondiente en la solicitud agregando el encabezado x-amz-security-token
.
Al obtener credenciales de seguridad temporales con la API de AWS Security Token Service, la respuesta incluye credenciales de seguridad temporales y un token de sesión. El valor del token de la sesión lo facilita en el encabezado x-amz-security-token
al enviar solicitudes a Amazon S3. Para obtener más información acerca de la API de AWS Security Token Service proporcionada por IAM, consulte la sección Acción en la Guía de referencia de la API de AWS Security Token Service.
El encabezado de autenticación
La API de REST de Amazon S3 usa el encabezado estándar HTTP Authorization
para transmitir la información de autenticación. (El nombre "encabezado estándar" no es demasiado preciso, ya que lo que transmite es información de autenticación, no autorización). Según el esquema de autenticación de Amazon S3, el encabezado de autorización tiene la siguiente forma:
Authorization: AWS
AWSAccessKeyId
:Signature
Los desarrolladores reciben una ID de clave de acceso de AWS y una clave de acceso secreta de AWS cuando se registran. Para la autenticación de solicitudes, el elemento AWSAccessKeyId
identifica la ID de clave de acceso utilizada para computar la firma e, indirectamente, también al desarrollador que realiza la solicitud.
El elemento Signature
es el RFC 2104 HMAC-SHA1 de los elementos seleccionados de la solicitud, y por tanto, la parte Signature
del encabezado de la autorización variará entre solicitudes. Si la firma de la solicitud calculada por el sistema coincide con la Signature
incluida en la solicitud, el solicitante habrá demostrado la posesión de la clave de acceso secreta de AWS. La solicitud será procesada bajo la identidad y con la autoridad del desarrollador al que se le emitió la clave.
A continuación presentamos pseudogramática que ilustra la construcción del encabezado de solicitudes Authorization
. (en el ejemplo, \n
representa el punto de código en Unicode U+000A
, normalmente denominado nueva línea).
Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of(YourSecretAccessKey), UTF-8-Encoding-Of( StringToSign ) ) ); StringToSign = HTTP-Verb + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedAmzHeaders + CanonicalizedResource; CanonicalizedResource = [ "/" + Bucket ] + <HTTP-Request-URI, from the protocol name up to the query string> + [ subresource, if present. For example "?acl", "?location", or "?logging"]; CanonicalizedAmzHeaders = <described below>
HMAC-SHA1 es un algoritmo definido por RFC 2104, código de autenticación de mensajes en clave-hashYourSecretAccessKey
) como clave y la codificación UTF-8 de StringToSign
como mensaje. El resultado del HMAC SHA1 también es una cadena de bytes, denominada resumen. El parámetro Signature
de la solicitud se construye en Base64 mediante la codificación de este resumen.
Solicitar canonicalización para firmas
Recuerde que cuando el sistema recibe una solicitud autenticada, compara la firma de la solicitud computada con la firma proporcionada en la solicitud en StringToSign
. Por este motivo, se debe computar la firma utilizando el mismo método que use Amazon S3. Al proceso de poner una solicitud en una forma acordada para la firma se le denomina canonicalización.
Crear elemento CanonicalizedResource
CanonicalizedResource
representa el recurso de Amazon S3 que es el destino de la solicitud. Debe construirlo para adaptarlo a una solicitud REST de la siguiente forma:
1 |
Comience por una cadena vacía ( |
2 |
Si la solicitud especifica un bucket con el encabezado del host HTTP (estilo de alojamiento virtual), adjunte el nombre del bucket precedido por un Para una solicitud de tipo alojamiento virtual "https://awsexamplebucket1.s3.us-west-1.amazonaws.com/photos/puppy.jpg", el Para la solicitud de tipo ruta, "https://s3.us-west-1.amazonaws.com/awsexamplebucket1/photos/puppy.jpg", el |
3 |
Adjunte la parte de la ruta del URI de la solicitud HTTP sin descodificar, hasta la cadena de la consulta, sin incluirla. Para una solicitud de tipo alojamiento virtual "https://awsexamplebucket1.s3.us-west-1.amazonaws.com/photos/puppy.jpg", el Para una solicitud de tipo ruta, "https://s3.us-west-1.amazonaws.com/awsexamplebucket1/photos/puppy.jpg", el Para una solicitud que no se dirija a un bucket, como GET Service, adjunte "/". |
4 |
Si la solicitud se dirige a un subrecurso, como Los subrecursos que se deben incluir cuando se crea el elemento CanonicalizedResource son los siguientes: acl, lifecycle, location, logging, notification, partNumber, policy, requestPayment, uploadId, uploads, versionId, versioning, versions y website. Si la solicitud especifica parámetros de la cadena de consulta que sobrescriban a los valores del encabezado de respuesta (véase Get Object), adjunte los parámetros de la cadena de consulta y sus valores. Al firmar no estará codificando estos valores. Sin embargo, al realizar la solicitud, debe codificar estos valores de parámetros. Los parámetros de la cadena de consulta en una solicitud GET incluyen El parámetro de la cadena de consulta |
Los elementos del CanonicalizedResource que provienen del URI de la solicitud HTTP deben firmarse literalmente según aparecen en la solicitud HTTP, incluidos los caracteres meta de codificación de la URL.
El CanonicalizedResource
podría ser diferente del URI de la solicitud HTTP. En particular, si su solicitud usa el encabezado HTTP Host
para especificar un bucket, el bucket no aparecerá en el URI de la solicitud HTTP. Sin embargo, el CanonicalizedResource
seguirá incluyendo el bucket. Los parámetros de la cadena de consulta podrían aparecer también en el URI de la solicitud, pero no están incluidos en el CanonicalizedResource
. Para obtener más información, consulte Alojamiento virtual de buckets.
Crear el elemento CanonicalizedAmzHeaders
Para construir la parte de CanonicalizedAmzHeaders de StringToSign
, seleccione todos los encabezados de las solicitudes HTTP que comiencen por "x-amz" (con una comparación que no distinga mayúsculas y minúsculas) y emplee el siguiente proceso.
1 | Convierta cada nombre de encabezado HTTP a minúsculas. Por ejemplo, "X-Amz-Date " se ha de convertir en "x-amz-date ". |
2 | Ordene la colección de encabezados lexicográficamente por nombre de encabezado. |
3 | Combine los campos de encabezado que tengan el mismo nombre en un par de encabezados "nombre-de-encabezado:lista-de-valores-separados-por-comas" según se indica en la RFC 2616, sección 4.2, sin espacios entre los valores. Por ejemplo, dos encabezados de metadatos "x-amz-meta-username: fred " y "x-amz-meta-username: barney " se combinarían en el encabezado único "x-amz-meta-username:
fred,barney ". |
4 | "Desdoble" los encabezados largos que ocupen varias líneas (según lo permite la RFC 2616, sección 4.2) sustituyendo el espacio de desdoble (incluida la línea nueva) por un espacio único. |
5 | Elimine los espacios que haya en torno a los dos puntos del encabezado. Por ejemplo, el encabezado "x-amz-meta-username: fred,barney " se convertiría en "x-amz-meta-username:fred,barney ". |
6 | Por último, adjunte un nuevo carácter (U+000A ) a cada encabezado canonicalizado de la lista resultante. Construye el elemento CanonicalizedResource concatenando todos los encabezados de esta lista en una cadena única. |
Elementos StringToString de los encabezados HTTP: posicionales frente a denominados
Los primeros elementos del encabezado de StringToSign
(Content-Type, Date y Content-MD5) tienen naturaleza posicional. StringToSign
no incluye los nombres de estos encabezados, solo sus valores procedentes de la solicitud. Por contraste, los elementos "x-amz-
" son denominados. Tanto los nombres como los valores de los encabezados aparecen en StringToSign
.
Si un encabezado posicional al que se llama en la definición de StringToSign
no está presente en su solicitud (por ejemplo, Content-Type
o Content-MD5
son opcionales para las solicitudes PUT y no significativos para la solicitudes GET), sustituya la cadena vacía ("") para dicha posición.
Requisitos de marca temporal
Una marca temporal válida (en la que se use el encabezado HTTP Date
o una alternativa x-amz-date
) es obligatoria para las solicitudes autenticadas. Además, la marca temporal del cliente incluida en una solicitud autenticada debe estar en el intervalo de 15 minutos del momento, según la hora del sistema de Amazon S3 en el que se recibe la solicitud. En caso contrario, ocurrirá un error en la solicitud y recibirá el código de error RequestTimeTooSkewed
. El objetivo de estas restricciones es limitar la posibilidad de que las solicitudes interceptadas pudieran ser reproducidas por un adversario. Para implementar una protección más sólida ante el acceso no autorizado, use el transporte HTTPS para solicitudes autenticadas.
nota
La limitación de validación con la fecha de solicitud solo se aplica a las solicitudes autenticadas en las que no se use la autenticación por cadena de consulta. Para obtener más información, consulte Alternativa de autenticación por cadena de consulta de solicitudes.
Algunas bibliotecas de cliente HTTP no permiten configurar el encabezado Date
para una solicitud. Si encuentra problemas al incluir el valor del encabezado "Date" en los encabezados canonicalizados, puede establecer la marca temporal de la solicitud mediante un encabezado "x-amz-date
". El valor del encabezado x-amz-date
debe encontrarse en uno de los formatos que se indican en RFC 2616 (http://www.ietf.org/rfc/rfc2616.txtx-amz-date
presente en una solicitud, el sistema ignorará cualquier encabezado Date
al computarla firma de la misma. Por tanto, si incluye el encabezado x-amz-date
, use la cadena vacía para Date
al construir el StringToSign
. Consulte la siguiente sección para ver un ejemplo.
Ejemplos de autenticación
Los ejemplos de esta sección emplean las credenciales (no funcionales) de la siguiente tabla.
Parámetro | Valor |
---|---|
AWSAccessKeyId | AKIAIOSFODNN7EXAMPLE |
AWSSecretAccessKey | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
En el ejemplo, el formato de StringToSign
no es significativo, y el \n
es el punto de código Unicode U+000A
, normalmente denominado línea nueva. Además, en los ejemplos se usa "+0000" para designar la zona horaria. También puede usar "GMT" para designar la zona horaria, pero las firmas que se mostrarán en los ejemplos serán diferentes.
Object GET
En este ejemplo se obtiene un objeto del bucket awsexamplebucket1.
Solicitud | StringToSign |
---|---|
|
|
Tenga en cuenta que el CanonicalizedResource incluye el nombre del bucket, pero la URI de la solicitud HTTP no. (El encabezado del host especifica el bucket).
nota
La siguiente secuencia de comandos de Python calcula la firma anterior, utilizando los parámetros proporcionados. Puede utilizar este script para construir sus propias firmas, reemplazando las claves y StringToSign según corresponda.
import base64 import hmac from hashlib import sha1 access_key = '
AKIAIOSFODNN7EXAMPLE
'.encode("UTF-8") secret_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
'.encode("UTF-8") string_to_sign = 'GET\n\n\nTue, 27 Mar 2007 19:36:42 +0000\n/awsexamplebucket1/photos/puppy.jpg
'.encode("UTF-8") signature = base64.b64encode( hmac.new( secret_key, string_to_sign, sha1 ).digest() ).strip() print(f"AWS {access_key.decode()}:{signature.decode()}")
Object PUT
En este ejemplo se coloca un objeto en el bucket awsexamplebucket1.
Solicitud | StringToSign |
---|---|
|
|
Tenga en cuenta el encabezado Content-Type en la solicitud y en el StringToSign. Tenga en cuenta también que el Content-MD5 se deja vacío en el StringToSign, porque no aparece en la solicitud.
Enumeración
En este ejemplo se muestra el contenido del bucket awsexamplebucket1.
Solicitud | StringToSign |
---|---|
|
|
Tenga en cuenta la barra al final del CanonicalizedResource y la ausencia de parámetros en la cadena de consulta.
Fetch
En este ejemplo se obtiene el subrecurso de la política de control de acceso para el bucket "awsexamplebucket1".
Solicitud | StringToSign |
---|---|
|
|
Ahora, tenga en cuenta cómo el parámetro de la cadena de consulta del subrecurso está incluido en el CanonicalizedResource.
Delete
En este ejemplo se elimina un objeto del bucket "awsexamplebucket1" de tipo ruta y la alternativa Date.
Solicitud | StringToSign |
---|---|
|
|
Tenga en cuenta que hemos usado el método alternativo "x-amz-date" para especificar la fecha (porque nuestra biblioteca de clientes, por ejemplo, nos impide establecer la fecha). En este caso, el x-amz-date
tiene prioridad sobre el encabezado Date
. Por tanto, la fecha introducida en la firma ha de contener el valor del encabezado x-amz-date
.
Cargar
En este ejemplo se carga un objeto en un bucket con alojamiento virtual de estilo CNAME y con metadatos.
Solicitud | StringToSign |
---|---|
|
|
Tenga en cuenta cómo los encabezados "x-amz-" se ordenan, se les recortan los espacios extra o se convierten en minúscula. Tenga en cuenta también que se han agrupado varios encabezados con el mismo nombre utilizando comas para separar valores.
Tenga en cuenta que solo los encabezados de entidades HTTP Content-Type
y Content-MD5
aparecen en el StringToSign
. El resto de encabezados de entidades Content-*
no aparecen.
Además, tenga en cuenta que el CanonicalizedResource
incluye el nombre del bucket, pero el URI de la solicitud HTTP no lo incluye. (El encabezado del host especifica el bucket).
Mostrar todos mis buckets
Solicitud | StringToSign |
---|---|
|
|
Claves de Unicode
Solicitud | StringToSign |
---|---|
|
|
nota
Los elementos en el StringToSign
que se derivaron del URI de la solicitud se toman literalmente, incluida la codificación y capitalización de la URL.
Problemas de firma con solicitudes REST
Cuando falla la autenticación de REST, el sistema responde a la solicitud con un documento de errores XML. La información que contiene este documento de errores tiene como objetivo ayudar a los desarrolladores a diagnosticar el problema. En particular, el elemento StringToSign
del documento de errores SignatureDoesNotMatch
le dice exactamente qué canonicalización de solicitudes está empleando el sistema.
Algunas herramientas insertan encabezados en modo silencioso cuya existencia usted no conocía, como la agregación del encabezado Content-Type
durante un PUT. En la mayoría de estos casos, el valor del encabezado insertado permanece constante, con lo que podrá descubrir los encabezados faltantes con herramientas como Ethereal o tcpmon.
Alternativa de autenticación por cadena de consulta de solicitudes
Puede autenticar determinado tipo de solicitudes pasando la información requerida como parámetros de una cadena de consulta, en lugar de usar el encabezado HTTP Authorization
. Esto resulta útil para habilitar el acceso directo por navegador de terceros a sus datos de Amazon S3 privados sin hacer pasar la solicitud por un proxy. La idea es construir una solicitud "prefirmada" y codificarla como una URL que pueda recuperar el navegador de un usuario final. Además, puede limitar una solicitud prefirmada especificando una fecha de vencimiento.
Para obtener más información acerca del uso de parámetros de consulta para autenticar solicitudes, consulte Autenticación de solicitudes: Uso de los parámetros de consulta(AWS Signature Version 4) en la Referencia de la API de Amazon Simple Storage Service. Con el fin de ver ejemplos sobre cómo usar los SDK de AWS para generar URL prefirmadas, consulte Uso compartido de objetos con URL prefirmadas.
Crear una firma
A continuación figura un ejemplo de una solicitud REST de Amazon S3 autenticada por cadena de consulta.
GET /photos/puppy.jpg ?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D HTTP/1.1 Host: awsexamplebucket1.s3.us-west-1.amazonaws.com Date: Mon, 26 Mar 2007 19:37:58 +0000
El método de autenticación de solicitudes con cadena de consulta no requiere ningún encabezado HTTP especial. Los elementos de autenticación necesarios se especifican como parámetros de la cadena de consulta:
Nombre del parámetro de la cadena de consulta | Ejemplo de valor | Descripción |
---|---|---|
AWSAccessKeyId |
AKIAIOSFODNN7EXAMPLE |
El ID de la clave de acceso de AWS. Especifica la clave de acceso secreta de AWS utilizada para firmar la solicitud e, indirectamente, la identidad del desarrollador que realiza la solicitud. |
Expires |
1141889120 |
El momento de vencimiento de la firma, especificado como el número de segundos a partir de la fecha de inicio (00:00:00 UTC del 1 de enero de 1970). Cualquier solicitud recibida con posterioridad a este momento (según el servidor) será rechazada. |
Signature |
vjbyPxybdZaNmGa%2ByT272YEAiv4%3D |
La codificación URL de la codificación Base64 del HMAC SHA1 de StringToSign. |
El método de autenticación de solicitudes con cadena de consulta difiere levemente del método ordinario, pero solo en el formato del parámetro de la solicitud Signature
y el elemento StringToSign
. A continuación presentamos pseudogramática que ilustra el método de autenticación de solicitudes por cadena de consulta.
Signature = URL-Encode( Base64( HMAC-SHA1( YourSecretAccessKey, UTF-8-Encoding-Of( StringToSign ) ) ) ); StringToSign = HTTP-VERB + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Expires + "\n" + CanonicalizedAmzHeaders + CanonicalizedResource;
YourSecretAccessKey
es el ID de clave de acceso secreta de AWS que le asigna Amazon cuando se registra para ser un desarrollador de Amazon Web Services. Tenga en cuenta que la Signature
está codificada en formato de URL para que se pueda colocar en la cadena de consulta. Tenga en cuenta también que, en StringToSign
, el elemento posicional HTTP Date
ha sido sustituido por Expires
. El CanonicalizedAmzHeaders
y el CanonicalizedResource
son iguales.
nota
En el método de autenticación por cadena de consulta, no utilice el encabezado Date
ni x-amz-date request
al calcular la cadena para firmar.
Autenticación por cadena de consulta de solicitudes
Solicitud | StringToSign |
---|---|
|
|
Suponemos que, cuando un navegador realiza la solicitud GET, no facilitará un encabezado Content-MD5 ni Content-Type, ni tampoco creará encabezados x-amz-, por lo que esas partes de StringToSign
se dejan vacías.
Usar codificación Base64
Las firmas de solicitudes HMAC deben tener codificación Base64. La codificación Base64 convierte la firma en una cadena ASCII sencilla que se puede adjuntar a la solicitud. Los caracteres que podrían aparecer en la cadena de firma, como más (+), barra inclinada (/) e igual (=) deben estar codificados si se usan en un URI. Por ejemplo, si el código de autenticación incluye un signo más (+), codifíquelo como %2B en la solicitud. Las barras inclinadas se codifican como %2F, y los signos de igual, como %3D.
Para ver más ejemplos de codificación en Base64, consulte los de Amazon 3 Ejemplos de autenticación.