Crie uma solicitação assinada de API da AWS - AWS Identity and Access Management

Crie uma solicitação assinada de API da AWS

Importante

Caso use um SDK da AWS (consulte Código de exemplo e bibliotecas) ou a ferramenta AWS Command Line Interface (AWS CLI) para enviar solicitações de API à AWS, você pode pular esta seção, pois os clientes do SDK e CLI autenticam as solicitações usando as chaves de acesso fornecidas por você. A menos que haja um bom motivo para não usar, é recomendável usar sempre um SDK ou a CLI.

Em regiões compatíveis com várias versões de assinatura, assinar as solicitações manualmente significa que é necessário especificar qual versão de assinatura está sendo usada. Quando você fornece solicitações para pontos de acesso multirregionais, os SDKs e a CLI automaticamente alternam para o uso do Signature Version 4A, sem configuração adicional.

Você pode usar o protocolo de assinatura SigV4 da AWS para criar uma solicitação assinada para solicitações de API da AWS.

  1. A criação de uma solicitação canônica com base nos detalhes da solicitação.

  2. O cálculo uma assinatura usando suas credenciais da AWS.

  3. Adicionar essa assinatura à solicitação como um cabeçalho de autorização.

A AWS, em seguida, replica esse processo e verifica a assinatura, concedendo ou negando o acesso adequadamente.

Para ver como você pode usar o AWS SigV4 para assinar solicitações de API, consulte Exemplos de assinatura de solicitação.

A tabela a seguir descreve as funções usadas no processo de criação de uma solicitação assinada. É necessário implementar o código para essas funções. Para obter mais informações, consulte os exemplos de código nos AWS SDKs.

Função Descrição

Lowercase()

Converta a string em letras minúsculas.

Hex()

Codificação de base 16 em letras minúsculas.

SHA256Hash()

Função de hash criptográfico do Secure Hash Algorithm (SHA).

HMAC-SHA256()

Calcula o HMAC usando o algoritmo SHA256 com a chave de assinatura fornecida. Esta é a assinatura final quando você assina com o SigV4.

ECDSA-Sign

Assinatura do Algoritmo de assinatura digital de curva elíptica (ECDSA) calculada usando assinaturas assimétricas baseadas em criptografia de chave pública-privada.

KDF(K, Label, Context, L)

Um KDF NIST SP800-108 no Modo Contador usando a função PRF HMAC-SHA256, conforme definido no NIST SP 800-108r1.

Oct2Int(byte[ ])

Uma função de octeto para inteiro, conforme descrito no ANSI X9.62.

Trim()

Remova qualquer espaço em branco inicial e final.

UriEncode()

O URI codifica cada byte. O UriEncode() deve aplicar as seguintes regras:

  • O URI codifica cada byte, exceto os caracteres não reservados: “A”-“Z”, “a”-“z”, “0”-“9”, “-”, “.”, “_” e “~”.

  • O caractere de espaço é um caractere reservado e deve ser codificado como “%20” (e não como “+”).

  • Cada byte codificado por URI é formado por um “%” e o valor hexadecimal de dois dígitos do byte.

  • As letras no valor hexadecimal devem estar em maiúsculas; por exemplo, “%1A”.

  • Codifique o caractere de barra, “/”, em todos os lugares, exceto no nome da chave do objeto. Por exemplo, se o nome da chave do objeto for photos/Jan/sample.jpg, a barra no nome da chave não está codificada.

Importante

As funções UriEncode padrão fornecidas por sua plataforma de desenvolvimento podem não funcionar devido às diferenças na implementação e à ambiguidade relacionada nos RFCs subjacentes. É recomendável escrever sua própria função UriEncode personalizada para garantir que a codificação funcione.

Para ver um exemplo de uma função UriEncode em Java, consulte Java Utilities no site do GitHub.

nota

Ao assinar as solicitações, você pode usar o AWS SigV4 ou o AWS SigV4a. A principal diferença entre os dois está na forma como a assinatura é calculada. Com o SigV4a, o conjunto de regiões é incluído na string a ser assinada, mas não faz parte da etapa de derivação da credencial.

Solicitação de assinatura com credenciais de segurança temporárias

Em vez de usar credenciais de longo prazo para assinar uma solicitação, é possível usar credenciais de segurança temporárias fornecidas pelo AWS Security Token Service (AWS STS).

Ao usar credenciais de segurança temporárias, é necessário adicionar o código X-Amz-Security-Token ao cabeçalho de autorização ou incluí-lo na string de consulta para manter o token da sessão. Alguns serviços exigem que você adicione X-Amz-Security-Token à solicitação canônica. Outros serviços exigem apenas que você adicione X-Amz-Security-Token no final, depois de calcular a assinatura. Verifique a documentação de cada AWS service (Serviço da AWS) para obter requisitos específicos.

Resumo das etapas de assinatura

Criar uma solicitação canônica

Organize o conteúdo da solicitação (host, ação, cabeçalhos etc.) em um formato padrão canônico. A solicitação canônica é um recurso usado para criar a string para assinar. Para obter detalhes sobre a criação da solicitação canônica, consulte Elementos de uma assinatura de solicitação de API da AWS.

Criar um hash para a solicitação canônica

Faça o hash da solicitação canônica usando o mesmo algoritmo que você usou para criar o hash da carga útil. O hash da solicitação canônica é uma string de caracteres hexadecimais em minúsculas.

Criar uma string para assinar

Crie uma string para assinar com a solicitação canônica e informações adicionais, como o algoritmo, data de solicitação, escopo de credencial e o hash da solicitação canônica.

Derivar uma chave de assinatura

Use a chave de acesso secreta para derivar a chave usada para assinar a solicitação.

Calcular a assinatura

Realize uma operação de hash com chave na string para assinar usando a chave de assinatura derivada como a chave de hash.

Adicionar a assinatura à solicitação

Adicione a assinatura calculada a um cabeçalho de HTTP ou à string de consulta da solicitação.

Criar uma solicitação canônica

Para criar uma solicitação canônica, concatene as strings a seguir separadas por caracteres de linha nova. Isso ajuda a garantir que a assinatura que você calcula possa corresponder à assinatura que a AWS calcula.

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

  • CanonicalUri: a versão codificada em URI do componente de caminho absoluto do URI, começando com o código / que segue o nome do domínio e indo até o final da string ou até o caractere de ponto de interrogação (?) se você tiver parâmetros de string de consulta. Se o caminho absoluto estiver vazio, use um caractere de barra inclinada (/). O URI no exemplo a seguir, /amzn-s3-demo-bucket/myphoto.jpg, é o caminho absoluto, e você não codifica o / no caminho absoluto:

    http://s3.amazonaws.com/amzn-s3-demo-bucket/myphoto.jpg
  • CanonicalQueryString: os parâmetros da string de consulta codificados por URI. Codifique por URI cada nome e valor individualmente. Também é necessário classificar os parâmetros na string de consulta canônica em ordem alfabética pelo nome da chave. A classificação ocorre após a codificação. A string de consulta no seguinte exemplo de URI é:

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

    A string de consulta canônica é como este exemplo (quebras de linha foram adicionadas ao exemplo para facilitar a leitura):

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

    Quando uma solicitação se destina a um sub-recurso, o valor do parâmetro de consulta correspondente é uma string vazia (""). Por exemplo, o URI a seguir identifica o sub-recurso ACL no bucket amzn-s3-demo-bucket:

    http://s3.amazonaws.com/amzn-s3-demo-bucket?acl

    Nesse caso, a CanonicalQueryString seria:

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

    Caso o URI não contenha um ?, não há strings de consulta na solicitação, e você define a string de consulta canônica como uma string vazia (""). Você ainda precisará incluir o caractere de linha nova ("\n").

  • CanonicalHeaders: uma lista de cabeçalhos de solicitação com os respectivos valores. Os pares individuais de nome e valor do cabeçalho são separados pelo caractere de linha nova ("\n"). Veja a seguir um exemplo de um CanonicalHeader:

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

    A lista CanonicalHeaders deve conter:

    • Cabeçalho HTTP host

    • Se o cabeçalho Content-Type estiver presente na solicitação, você deverá adicioná-lo à lista CanonicalHeaders.

    • Também deverão ser adicionados todos os cabeçalhos x-amz-* que você pretende incluir na solicitação. Por exemplo, se você estiver usando credenciais de segurança temporárias, precisará incluir o x-amz-security-token na solicitação. É necessário adicionar esse cabeçalho à lista de CanonicalHeaders.

    • Para SigV4a, você deve incluir um cabeçalho de conjunto de regiões que especifique o conjunto de regiões em que a solicitação será válida. O cabeçalho X-Amz-Region-Set é especificado como uma lista de valores separados por vírgula. O exemplo a seguir mostra um cabeçalho de região que permite fazer uma solicitação nas regiões us-east-1 e us-west-1.

      X-Amz-Region-Set=us-east-1,us-west-1

      Você pode usar curingas (*) em regiões para especificar várias regiões. No exemplo a seguir, o cabeçalho permite que uma solicitação seja feita tanto na região us-west-1 quanto na us-west-2.

      X-Amz-Region-Set=us-west-*

    nota

    O cabeçalho x-amz-content-sha256 é obrigatório para solicitações da AWS do Amazon S3. Ele fornece um hash da carga da solicitação. Se não houver carga útil, será necessário fornecer o hash de uma string vazia.

    Todo nome de cabeçalho deve:

    • usar caracteres minúsculos.

    • ser exibido em ordem alfabética.

    • ser seguido por dois pontos (:).

    Para valores, é necessário:

    • remover todos os espaços à esquerda ou à direita.

    • converter espaços sequenciais em um espaço único.

    • separar os valores de um cabeçalho de múltiplos valores usando vírgulas.

    • É necessário incluir na assinatura o cabeçalho host (HTTP/1.1) ou o cabeçalho :authority (HTTP/2) e quaisquer cabeçalhos x-amz-*. Opcionalmente, você pode incluir outros cabeçalhos padrão na assinatura, como content-type.

    As funções Lowercase() e Trim() usadas neste exemplo estão descritas na seção anterior.

    Veja a seguir um exemplo de string CanonicalHeaders. O nomes dos cabeçalhos estão em letras minúsculas e são classificados.

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

    nota

    Para fins de cálculo de uma assinatura de autorização, somente o host e cabeçalhos x-amz-* são obrigatórios; no entanto, para evitar a adulteração de dados, considere incluir os cabeçalhos adicionais no cálculo da assinatura.

    Não inclua cabeçalhos hop-by-hop que são alterados com frequência durante o trânsito em um sistema complexo. Isso inclui todos os cabeçalhos de transporte voláteis que são alterados por proxies, balanceadores de carga e nós em um sistema distribuído, incluindo connection, x-amzn-trace-id, user-agent, keep-alive, transfer-encoding, TE, trailer, upgrade, proxy-authorization e proxy-authenticate.

  • SignedHeaders: uma lista ordenada alfabeticamente, separada por ponto e vírgula, de nomes de cabeçalhos de solicitação em letras minúsculas. Os cabeçalhos de solicitação da lista são os mesmos cabeçalhos que você incluiu na string CanonicalHeaders. Para o exemplo anterior, o valor de SignedHeaders seria:

    host;x-amz-content-sha256;x-amz-date
  • HashedPayload: uma string criada usando a carga útil no corpo da solicitação HTTP como entrada para uma função de hash. Esta string usa caracteres hexadecimais minúsculos.

    Hex(SHA256Hash(<payload>>))

    Se não houver carga útil na solicitação, calcule um hash da string vazia. Por exemplo, ao recuperar um objeto usando uma solicitação GET, não haverá nada na carga útil.

    Hex(SHA256Hash(""))
    nota

    Para o Amazon S3, inclua a string literal UNSIGNED-PAYLOAD ao construir uma solicitação canônica e defina o mesmo valor como o cabeçalho x-amz-content-sha256 ao enviar a solicitação.

    Hex(SHA256Hash("UNSIGNED-PAYLOAD"))

Criar um hash para a solicitação canônica

Crie um hash (resumo) da solicitação canônica usando o mesmo algoritmo que você usou para criar o hash da carga útil. O hash da solicitação canônica é uma string de caracteres hexadecimais em minúsculas.

Criar uma string para assinar

Para criar uma string para assinar, concatene as strings a seguir separadas por caracteres de linha nova. Não termine esta string com um caractere de linha nova.

Algorithm \n RequestDateTime \n CredentialScope \n HashedCanonicalRequest
  • Algorithm: o algoritmo usado para criar o hash da solicitação canônica.

    • SigV4: use AWS4-HMAC-SHA256 para especificar o algoritmo de hash HMAC-SHA256.

    • SigV4a: use AWS4-ECDSA-P256-SHA256 para especificar o algoritmo de hash ECDSA-P256-SHA-256.

  • RequestDateTime: a data e a hora usadas no escopo da credencial. Esse valor é a hora UTC atual no formato ISO 8601 (por exemplo, 20130524T000000Z).

  • CredentialScope: o escopo de credencial, que restringe a assinatura resultante à região e ao serviço especificados.

    • SigV4: as credenciais incluem o ID da chave de acesso, a data no formato YYYYMMDD, o código da região, o código do serviço e a string aws4_request de término separados por barras (/). O código da região, o código do serviço e a string de término devem usar caracteres minúsculos. A string tem o seguinte formato: YYYYMMDD/region/service/aws4_request.

    • SigV4a: as credenciais incluem a data no formato YYYYMMDD, o nome do serviço e a string aws4_request de término separados por barras (/). Observe que o escopo da credencial não inclui a região, pois ela é englobada em um cabeçalho X-Amz-Region-Set separado. A string tem o seguinte formato: YYYYMMDD/service/aws4_request.

  • HashedCanonicalRequest: o hash da solicitação canônica, calculada na etapa anterior.

Veja a seguir um exemplo de string para assinar.

"<Algorithm>" + "\n" + timeStampISO8601Format + "\n" + <Scope> + "\n" + Hex(<Algorithm>(<CanonicalRequest>))

Derivar uma chave de assinatura

Para derivar uma chave de assinatura, escolha um dos processos a seguir para calcular uma chave de assinatura para SigV4 ou SigV4a.

Derivar uma chave de assinatura para SigV4

Para derivar uma chave de assinatura para SigV4, realize uma sequência de operações de hash com chave (HMAC) no serviço, região e data da solicitação usando sua chave de acesso secreta da AWS como a chave para a operação inicial de hashing.

Para cada etapa, chame a função de hash com a chave e os dados necessários. O resultado de cada chamada para a função de hash torna-se a entrada para a próxima chamada para a função de hash.

O exemplo a seguir mostra como você deriva a SigningKey usada na próxima seção desse procedimento, mostrando a ordem na qual sua entrada é concatenada e transformada em hash. O código HMAC-SHA256 é a função de hash usada para fazer o hash dos dados, conforme mostrado.

DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>") DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>") SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")
Entrada obrigatória
  • Key: uma string que contém sua chave de acesso secreta.

  • Date: uma string que contém a data usada no escopo da credencial, no formato AAAAMMDD.

  • Region: uma string que contém o código da região (por exemplo, us-east-1).

    Para obter uma lista de regiões de strings, consulte Regional endpoints, na Referência geral da AWS.

  • Service: uma string que contém o código do serviço (por exemplo, ec2).

  • A string para assinar que você criou na etapa anterior.

Derivar uma chave de assinatura para SigV4
  1. Concatene "AWS4" e a chave de acesso secreta. Chame a função de hash com a string concatenada como chave e a string de data como os dados.

    DateKey = hash("AWS4" + Key, Date)
  2. Chame a função de hash com o resultado da chamada anterior como chave e a string de região como os dados.

    DateRegionKey = hash(kDate, Region)
  3. Chame a função de hash com o resultado da chamada anterior como a chave e a string de serviço como os dados.

    O código do serviço é definido pelo serviço. Você pode usar get-products na AWS Pricing CLI para retornar o código de serviço de um serviço.

    DateRegionServiceKey = hash(kRegion, Service)
  4. Chame a função de hash com o resultado da chamada anterior como a chave e “aws4_request” como os dados.

    SigningKey = hash(kService, "aws4_request")

Derivar uma chave de assinatura para SigV4a

Para criar uma chave de assinatura para SigV4a, use o processo a seguir para derivar um par de chaves da chave de acesso secreta. Para obter um exemplo de implementação dessa derivação, consulte a implementação da biblioteca C99 da autenticação do lado do cliente da AWS

n = [NIST P-256 elliptic curve group order] G = [NIST P-256 elliptic curve base point] label = "AWS4-ECDSA-P256-SHA256" akid = [AWS access key ID as a UTF8 string] sk = [AWS secret access Key as a UTF8 Base64 string] input_key = "AWS4A" || sk count = 1 while (counter != 255) { context = akid || counter // note: counter is one byte key = KDF(input_key, label, context, 256) c = Oct2Int(key) if (c > n - 2) { counter++ } else { k = c + 1 // private key Q = k * G // public key } } if (c < 255) { return [k, Q] } else { return FAILURE }

Calcular a assinatura

Depois de derivar a chave de assinatura, calcule a assinatura para adicionar à sua solicitação. Esse procedimento varia de acordo com a versão de assinatura que você usa.

Para calcular uma assinatura para SigV4
  1. Chame a função de hash com o resultado da chamada anterior como a chave e a string para assinar como os dados. Use a chave de assinatura derivada como a chave de hash para esta operação. O resultado é a assinatura como valor binário.

    signature = hash(SigningKey, string-to-sign)
  2. Converta a assinatura da representação binária em hexadecimal, em caracteres minúsculos.

Para calcular uma assinatura para SigV4a
  1. Usando o algoritmo de assinatura digital (ECDSA P-256), assine a string para assinar que você criou na etapa anterior. A chave usada para essa assinatura é a chave assimétrica privada derivada da chave de acesso secreta, conforme descrito acima.

    signature = base16(ECDSA-Sign(k, string-to-sign))
  2. Converta a assinatura da representação binária em hexadecimal, em caracteres minúsculos.

Adicionar a assinatura à solicitação

Adicione a assinatura calculada à sua solicitação.

exemplo Exemplo: cabeçalho de autorização
SigV4

O exemplo a seguir mostra um cabeçalho Authorization para a ação DescribeInstances usando o AWS SigV4. Para facilitar a leitura, este exemplo está formatado com quebras de linha. Em seu código, deve ser uma string contínua. Não há vírgula entre o algoritmo e Credential. Porém, os outros elementos devem ser separados por vírgulas.

Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=calculated-signature
Sigv4a

O exemplo a seguir mostra um cabeçalho Authorization para a ação CreateBucket usando o AWS SigV4a. Para facilitar a leitura, este exemplo está formatado com quebras de linha. Em seu código, deve ser uma string contínua. Não há vírgula entre o algoritmo e a credencial. Porém, os outros elementos devem ser separados por vírgulas.

Authorization: AWS4-ECDSA-P256-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220830/s3/aws4_request, SignedHeaders=host;x-amz-date;x-amz-region-set, Signature=calculated-signature
exemplo Exemplo: solicitação com parâmetros de autenticação na string de consulta
SigV4

O exemplo a seguir mostra uma consulta para a ação DescribeInstances usando o AWS SigV4 que contém as informações de autenticação. Para facilitar a leitura, esse exemplo está formatado com quebras de linha e não codificado de URL. Em seu código, a string de consulta deve ser uma string contínua codificada de 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
Sigv4a

O exemplo a seguir mostra uma consulta para a ação CreateBucket usando o AWS SigV4a que contém as informações de autenticação. Para facilitar a leitura, esse exemplo está formatado com quebras de linha e não codificado de URL. Em seu código, a string de consulta deve ser uma string contínua codificada de URL.

https://ec2.amazonaws.com/? Action=CreateBucket& Version=2016-11-15& X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256& X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20220830/s3/aws4_request& X-Amz-Region-Set=us-west-1& X-Amz-Date=20220830T123600Z& X-Amz-SignedHeaders=host;x-amz-date;x-amz-region-set& X-Amz-Signature=calculated-signature