AWS 一般参考
参考指南 (版本 1.0)
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

签名版本 2 签名流程

您可以使用签名版本 2 签署 API 请求。但是,我们建议您使用Signature Version 4 签署您的请求。有关更多信息,请参阅 Signature Version 4 签名流程

受支持的区域和服务

您可以使用签名版本 2 为某些 AWS 区域中的某些 AWS 服务签署 API 请求。否则,您必须使用 Signature Version 4 对 API 请求进行签名。

支持签名版本 2 的区域

  • 美国东部(弗吉尼亚北部)地区

  • 美国西部(加利福利亚北部)区域

  • 美国西部(俄勒冈)区域

  • 欧洲(爱尔兰)区域

  • 亚太区域(东京)

  • 亚太区域(新加坡)

  • 亚太区域(悉尼)

  • 南美洲(圣保罗)区域

支持签名版本 2 的服务

  • Amazon EC2 Auto Scaling

  • AWS CloudFormation

  • Amazon CloudWatch

  • AWS Elastic Beanstalk

  • Amazon Elastic Compute Cloud (Amazon EC2)

  • Elastic Load Balancing

  • Amazon EMR

  • Amazon ElastiCache

  • AWS Identity and Access Management (IAM)

  • AWS Import/Export

  • Amazon Relational Database Service (Amazon RDS

  • Amazon Simple Notification Service (Amazon SNS)

  • Amazon Simple Queue Service (Amazon SQS)

  • Amazon SimpleDB

签名版本 2 的查询请求组件

AWS 要求采用签名版本 2 格式的每个 HTTP 或 HTTPS 查询请求都包含以下内容:

终端节点

也称为 HTTP 请求的主机部分。这是您发送查询请求的计算机的 DNS 名称。它对于每个 AWS 区域是不同的。有关每种服务的终端节点列表,请参阅AWS 服务终端节点

操作

您希望 Web 服务执行的操作。这个值用于确定在请求中使用的参数。

AWSAccessKeyId

注册 AWS 账户时由 AWS 分配的值。

签名方法

用于计算签名的基于哈希的协议。它可以是适用于签名版本 2 的 HMAC-SHA1 或 HMAC-SHA256。

签名版本

AWS 签名协议的版本。

时间戳

您发出请求的时间。在查询请求中包含此值有助于防止第三方截取您的请求。

必需和可选参数

每个操作都有一组用于定义 API 调用的必需参数和可选参数。

签名

计算得出的值,用于确保签名有效和未被篡改。

下面是一个采用 HTTPS GET 请求格式的示例 Amazon EMR 查询请求。

  • 终端节点 elasticmapreduce.amazonaws.com.cn 是默认终端节点,它映射到区域 us-east-1。

  • 操作是 DescribeJobFlows,它请求有关一个或多个任务流程的信息。

注意

实际的查询请求中没有空格或换行符。请求是连续的文本行。下面的版本已经进行了格式设置,便于阅读。

https://elasticmapreduce.amazonaws.com.cn? &AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE &Action=DescribeJobFlows &SignatureMethod=HmacSHA256 &SignatureVersion=2 &Timestamp=2011-10-03T15%3A19%3A30 &Version=2009-03-31 &Signature=calculated value

如何为查询请求生成签名版本 2

Web 服务请求通过 Internet 发送,易被篡改。为了确保请求未被更改,AWS 会计算签名,以确定任何参数或参数值在传输途中是否发生了更改。AWS 要求把签名作为每个请求的一部分。

注意

请确保对该请求进行 URI 编码。例如,您请求中的空白应编码为 %20。虽然 HTTP 协议规范通常允许未编码的空格,但使用未编码的字符会使查询请求中的签名无效。请将空格编码为加号 (+),因为这会导致错误。

以下主题介绍使用 AWS 签名版本 2 计算签名所需的步骤。

任务 1:设置查询请求的格式

在对查询请求签名之前,请将请求设置为标准化 (规范) 格式。这是因为采用不同的方式设置查询请求格式会得到不同的 HMAC 签名。在签名前请将请求设置为规范格式。这可以确保您的应用程序和 AWS 将为请求计算出相同的签名。

要创建待签字符串,您需要连接查询请求组件。下面的示例为以下 Amazon EMR API 调用生成待签字符串。

https://elasticmapreduce.amazonaws.com.cn? Action=DescribeJobFlows &Version=2009-03-31 &AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE &SignatureVersion=2 &SignatureMethod=HmacSHA256 &Timestamp=2011-10-03T15:19:30

注意

前面请求中的最后四个参数(从 AWSAccessKeyID 到 Timestamp)称为身份验证参数。每个签名版本 2 请求中都需要这些参数。AWS 用它们确定谁发送请求以及是否授予请求的访问权限。

创建要签署的字符串的步骤(签名版本 2)

  1. 先是请求方法(GET 或 POST),然后是换行符。为便于阅读,换行符表示为 \n

    GET\n
  2. 添加小写的 HTTP 主机标头(终端节点),然后添加换行符。若为协议的标准端口(HTTP 端口 80 和 HTTPS 端口 443),可以省略端口信息;若为非标准端口,则需包含端口信息。

    elasticmapreduce.amazonaws.com.cn\n
  3. 添加 URI 的每个路径分段的 URL 编码版本(指的是 HTTP 主机标头到查询字符串参数开头的问号字符 (?) 之间的全部字符),后面加换行符。请勿编码用于划定每个路径分段的正斜杠 (/)。

    在本例中,如果绝对路径为空,请使用正斜杠 (/)。

    /\n
    1. 添加查询字符串组件,使用 UTF-8 字符形式,它们应进行了 URL 编码(十六进制字符必须大写)。您没有对请求中的初始问号字符 (?) 进行编码。有关更多信息,请参见 RFC 3986

    2. 按字节顺序对查询字符串组件排序。字节顺序区分大小写。AWS 根据原始字节对这些组件排序。

      例如,下面是查询字符串组件的原始顺序。

      Action=DescribeJobFlows Version=2009-03-31 AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE SignatureVersion=2 SignatureMethod=HmacSHA256 Timestamp=2011-10-03T15%3A19%3A30

      这些查询字符串组件会重新组织为以下顺序:

      AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE Action=DescribeJobFlows SignatureMethod=HmacSHA256 SignatureVersion=2 Timestamp=2011-10-03T15%3A19%3A30 Version=2009-03-31
    3. 使用等号字符 (=) 将参数名称与参数值分离,即使参数值为空也如此。使用与字符 (&) 分隔参数和值对。将参数及其值连接组成一个长字符串,中间没有空格。允许参数值内有空格,但空格必须经 URL 编码成 %20。在连接后的字符串中,句点字符 (.) 未进行转义。RFC 3986 将句点字符视为非保留字符,因此未对其进行 URL 编码。

      注意

      RFC 3986 没有指定对 ASCII 控制字符、扩展的 UTF-8 字符以及 RFC 1738 预留的其他字符作何处理。由于任何值都可能成为字符串值,这些其他字符应该进行百分数编码为 %XY,其中 X 和 Y 为大写的十六进制字符。扩展的 UTF-8 字符采用 %XY%ZA... 的形式(可以处理多字节)。

    下面的示例介绍查询字符串组件,参数采用与字符 (&) 连接,并按字节顺序排序。

    AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-3
  4. 要构建最终规范请求,请将每个步骤的所有组成部分组合起来。如下所示,每个组成部分都以换行符结尾。

    GET\n elasticmapreduce.amazonaws.com.cn\n /\n AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31

任务 2:计算签名

任务 1:设置查询请求的格式所述创建规范字符串后,使用 HMAC-SHA1 或 HMAC-SHA256 协议创建基于哈希的消息身份验证代码 (HMAC),然后计算签名。建议使用 HMAC-SHA256 协议。

在本例中,签名是使用以下规范字符串和私有密钥作为加密哈希函数的输入而计算的:

  • 规范查询字符串:

    GET\n elasticmapreduce.amazonaws.com.cn\n /\n AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31
  • 示例私有密钥:

    wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

所得签名必须采用 Base-64 编码。

i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf%2FMj6vPxyYIs%3D

将得到的值作为 Signature 参数添加到查询请求中。在将此参数添加到请求时,您必须像对任何其他参数一样对此参数进行 URI 编码。您可以在 HTTP 或 HTTPS 调用中使用已签名的请求。

https://elasticmapreduce.amazonaws.com.cn?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31&Signature=i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf%2FMj6vPxyYIs%3D

注意

您可以使用 AWS Security Token Service (AWS STS) 提供的临时安全证书对请求进行签名。此过程与使用长期凭证相同,但是请求需要安全令牌的其他参数。

以下请求使用临时访问密钥 ID 和 SecurityToken 参数。

例 具有临时安全凭证的示例请求

https://sdb.amazonaws.com.cn/ ?Action=GetAttributes &AWSAccessKeyId=access-key-from-AWS Security Token Service &DomainName=MyDomain &ItemName=MyItem &SignatureVersion=2 &SignatureMethod=HmacSHA256 &Timestamp=2010-01-25T15%3A03%3A07-07%3A00 &Version=2009-04-15 &Signature=signature-calculated-using-the-temporary-access-key &SecurityToken=session-token

有关详细信息,请参阅以下资源:

问题排查请求签名版本 2

本部分描述了您在最初开发代码生成签名以签署查询请求时可能看到的一些错误代码。

Web 服务中的 SignatureDoesNotMatch 签名错误

如果 Web 服务尝试通过重新计算签名值来验证请求签名,但生成的值与附加到请求的签名不匹配,将返回以下错误响应。这可能是因为在发送请求和请求到达 Web 服务终端节点的过程中,请求被修改(这就是签名要检测的情况),或者是因为签名计算错误。以下错误消息的常见原因是不恰当地创建了待签字符串,例如,忘记对 Amazon S3 存储桶名称中的一些字符进行 URL 编码,如冒号 (:) 和正斜杠 (/)。

<ErrorResponse xmlns="http://elasticmapreduce.amazonaws.com.cn/doc/2009-03-31"> <Error> <Type>Sender</Type> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message> </Error> <RequestId>7589637b-e4b0-11e0-95d9-639f87241c66</RequestId> </ErrorResponse>

Web 服务中的 IncompleteSignature 签名错误

以下错误表明该签名缺少信息或格式不正确。

<ErrorResponse xmlns="http://elasticmapreduce.amazonaws.com.cn/doc/2009-03-31"> <Error> <Type>Sender</Type> <Code>IncompleteSignature</Code> <Message>Request must contain a signature that conforms to AWS standards</Message> </Error> <RequestId>7146d0dd-e48e-11e0-a276-bd10ea0cbb74</RequestId> </ErrorResponse>

使用 Java 软件开发工具包签署查询请求

以下示例使用适用于 Java 的 AWS 开发工具包中的 amazon.webservices.common 软件包来生成 AWS 签名版本 2 查询请求签名。要做到这一点,这个包创建符合 RFC 2104 要求的 HMAC 签名。有关 HMAC 的更多信息,请参阅 HMAC:用于消息身份验证的哈希密钥

注意

Java 用作示例实施。您可以使用所选的编程语言实施 HMAC 算法以签署查询请求。

import java.security.SignatureException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import com.amazonaws.util.*; /** * This class defines common routines for generating * authentication signatures for AWS Platform requests. */ public class Signature { private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256"; /** * Computes RFC 2104-compliant HMAC signature. * * @param data * The signed data. * @param key * The signing key. * @return * The Base64-encoded RFC 2104-compliant HMAC signature. * @throws * java.security.SignatureException when signature generation fails */ public static String calculateRFC2104HMAC(String data, String key) throws java.security.SignatureException { String result; try { // Get an hmac_sha256 key from the raw key bytes. SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA256_ALGORITHM); // Get an hmac_sha256 Mac instance and initialize with the signing key. Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM); mac.init(signingKey); // Compute the hmac on input data bytes. byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8")); // Base64-encode the hmac by using the utility in the SDK result = BinaryUtils.toBase64(rawHmac); } catch (Exception e) { throw new SignatureException("Failed to generate HMAC : " + e.getMessage()); } return result; } }