任务 1:针对签名版本 4 创建规范请求
要开始签名过程,请创建一个字符串,其中包含来自标准(规范)格式的请求的信息。这可确保 AWS 在收到请求时计算出的签名与您计算出的签名相同。
按照此处的步骤创建请求的规范版本。否则,您的版本与AWS计算得到的版本将不匹配,请求将被拒绝。
以下示例演示了创建规范请求的伪代码。
例 规范请求伪代码
CanonicalRequest =
HTTPRequestMethod
+ '\n' +CanonicalURI
+ '\n' +CanonicalQueryString
+ '\n' +CanonicalHeaders
+ '\n' +SignedHeaders
+ '\n' + HexEncode(Hash(RequestPayload
))
在此伪代码中,Hash
表示生成消息摘要的函数,通常是 SHA-256。(在该过程稍后的阶段中,您将指定要使用的哈希算法。)HexEncode
表示以小写字母形式返回摘要的 base-16 编码的函数。例如,HexEncode("m")
返回值 6d
而不是 6D
。输入的每一个字节都必须表示为两个十六进制字符。
签名版本 4 不需要您使用特定字符编码来对规范请求进行编码。不过,一些 AWS 服务可能需要特定编码。有关更多信息,请参阅该服务的文档。
以下示例演示如何构造规范形式的 IAM 请求。原始请求在从客户端发送到AWS时可能看上去与此类似,不过此示例还不包括签名信息。
例 Request
GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1 Host: iam.amazonaws.com Content-Type: application/x-www-form-urlencoded; charset=utf-8 X-Amz-Date: 20150830T123600Z
前面的示例请求是一个 GET 请求(方法),它向 ListUsers
(主机)发出 AWS Identity and Access Management API(操作)调用。此操作采用 Version
参数。
要创建规范请求,请将以下来自每个步骤的部分连接为一个字符串:
-
首先是 HTTP 请求方法(
GET
、PUT
、POST
等),后跟换行符。例 请求方法
GET
-
添加规范 URI 参数,后跟换行符。规范 URI 是 URI 的绝对路径部分的 URI 编码版本,该版本是 URI 中的一切 - 从 HTTP 主机到开始查询字符串参数(如果有)的问号字符(“?”)。
根据 RFC 3986
标准化 URI 路径。移除冗余和相对路径部分。路径中每个部分都必须经 URI 编码两次(Amazon S3 除外,其仅 URI 编码一次)。 例 使用编码的规范 URI
/documents%2520and%2520settings/
注意 例外情况是,您没有使用规范的 URI 路径来提出 Amazon S3 请求。例如,如果您拥有包含名为
my-object//example//photo.user
的对象的存储桶,请使用该路径。如果将该路径标准化为my-object/example/photo.user
,则会导致请求失败。有关更多信息,请参阅 Amazon Simple Storage Service API 参考中的任务 1:创建规范请求。如果绝对路径为空,则使用正斜杠 (/)。在示例 IAM 请求中,URI 中的主机后没有任何内容,因此绝对路径为空。
例 规范 URI
/
-
添加规范查询字符串,后跟换行符。如果请求不包括查询字符串,请使用空字符串(实际上是空白行)。示例请求具有以下查询字符串。
例 规范查询字符串
Action=ListUsers&Version=2010-05-08
要构建规范查询字符串,请完成以下步骤:
-
按字符代码点以升序顺序对参数名称进行排序。具有重复名称的参数应按值进行排序。例如,以大写字母 F 开头的参数名称排在以小写字母 b 开头的参数名称之前。
-
根据以下规则对每个参数名称和值进行 URI 编码:
-
请勿对 RFC 3986
定义的任何非预留字符进行 URI 编码,这些字符包括:A-Z、a-z、0-9、连字符 (-)、下划线 (_)、句点 (.) 和波形符 (~)。 -
使用 %XY 对所有其他字符进行百分比编码,其中“X”和“Y”为十六进制字符(0-9 和大写字母 A-F)。例如,空格字符必须编码为 %20(不像某些编码方案那样使用“+”),扩展 UTF-8 字符必须采用格式
%XY%ZA%BC
。 -
对参数值中的任何等于 (=) 字符进行双重编码。
-
-
以排序后的列表中第一个参数名称开头,构造规范查询字符串。
-
对于每个参数,追加 URI 编码的参数名称,后跟等号字符 (=),再接 URI 编码的参数值。对没有值的参数使用空字符串。
-
在每个参数值后追加与字符 (&),列表中最后一个值除外。
查询 API 的一种方案是将所有请求参数放入查询字符串中。例如,对 Amazon S3 这样做可以创建预签名 URL。在这种情况下,规范查询字符串不能只包含请求的参数,还必须包含在签名流程中要使用的参数:哈希算法、凭证范围、日期和已签名标头参数。
下面的示例说明包含身份验证信息的查询字符串。该示例中为便于阅读添加了换行符,但在您的代码中,规范查询字符串必须是连续的一行文本。
例 查询字符串中的身份验证参数
Action=ListUsers& Version=2010-05-08& X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fiam%2Faws4_request& X-Amz-Date=20150830T123600Z& X-Amz-SignedHeaders=content-type%3Bhost%3Bx-amz-date
有关身份验证参数的更多信息,请参阅 任务 2:创建签名版本 4 的待签字符串。
注意 您可以使用 AWS Security Token Service (AWS STS) 提供的临时安全证书对请求进行签名。其过程与使用长期凭证相同,但在您添加签名信息到查询字符串时,您必须为安全令牌添加额外的查询参数。参数名称为
X-Amz-Security-Token
,参数值为 URI 编码的会话令牌(在您获取临时安全凭证时从 AWS STS 收到的字符串)。对于一些服务,您必须在规范(签名)查询字符串中包括
X-Amz-Security-Token
查询参数。对于其他服务,计算签名之后,您需要在末尾添加X-Amz-Security-Token
参数。有关详细信息,请参阅该服务的 API 参考文档。 -
-
添加规范标头,后跟换行符。规范标头包括您要包含在签名请求中的所有 HTTP 标头的列表。
对于 HTTP/1.1 请求,您必须至少包含
host
标头。标准标头(如content-type
)是可选的。对于 HTTP/2 请求,您必须包括:authority
标头,而不是host
标头。不同的服务可能需要其他标头。例 规范标头
content-type:application/x-www-form-urlencoded; charset=utf-8\n host:iam.amazonaws.com\n x-amz-date:20150830T123600Z\n
要创建规范标头列表,请将所有标头名称转换为小写形式并删除前导空格和尾随空格。将标头值中的连续空格转换为单个空格。
以下伪代码描述如何构造规范标头列表:
CanonicalHeaders =
CanonicalHeadersEntry0
+CanonicalHeadersEntry1
+ ... +CanonicalHeadersEntryN
CanonicalHeadersEntry = Lowercase(HeaderName
) + ':' + Trimall(HeaderValue
) + '\n'Lowercase
表示将所有字符转换为小写字母的函数。Trimall
函数删除值前后的多余空格并将连续空格转换为单个空格。通过按字符代码对(小写)标头排序,然后对标头名称进行迭代操作,来构建规范标头列表。根据以下规则构造每个标头:
-
追加小写标头名称,后跟冒号。
-
追加该标头的值的逗号分隔列表。请勿对有多个值的标头进行值排序。
-
追加一个新行(“
\n
”)。
下列示例对更复杂的一组标头及其规范形式进行比较:
例 原始标头
Host:iam.amazonaws.com\n Content-Type:application/x-www-form-urlencoded; charset=utf-8\n My-header1: a b c \n X-Amz-Date:20150830T123600Z\n My-Header2: "a b c" \n
例 规范形式
content-type:application/x-www-form-urlencoded; charset=utf-8\n host:iam.amazonaws.com\n my-header1:a b c\n my-header2:"a b c"\n x-amz-date:20150830T123600Z\n
注意 每个标头都后跟换行符,这意味着完整列表以换行符结束。
对于规范形式,进行了下列更改:
-
标头名称已转换为小写字符。
-
标头已按字符代码进行排序。
-
已从
my-header1
和my-header2
值中删除前导空格和尾随空格。 -
对于
a b c
和my-header1
值,已将my-header2
中的连续空格转换为单个空格。
注意 您可以使用 AWS Security Token Service (AWS STS) 提供的临时安全证书对请求进行签名。该过程与使用长期凭证相同,但在
Authorization
标头中包括签名信息时,必须为安全令牌添加额外的 HTTP 标头。标头名称为X-Amz-Security-Token
,标头值是会话令牌(在您获取临时安全凭证时从 AWS STS 收到的字符串)。 -
-
添加已签名的标头,后跟换行符。该值是您包含在规范标头中的标头列表。通过添加此标头列表,您可以向AWS告知请求中的哪些标头是签名过程的一部分,以及在验证请求时AWS可以忽略哪些标头(例如,由代理添加的任何附加标头)。
对于 HTTP/1.1 请求,
host
标头必须作为已签名标头包括在内。对于包含:authority
标头而不是host
标头的 HTTP/2 请求,必须包含:authority
标头作为已签名标头。如果包括日期或x-amz-date
标头,则还必须包括在已签名标头列表中的标头。要创建已签名标头列表,请将所有标头名称转换为小写形式,按字符代码对其进行排序,并使用分号来分隔这些标头名称。以下伪代码描述如何构建已签名标头的列表。
Lowercase
表示将所有字符转换为小写字母的函数。SignedHeaders = Lowercase(
HeaderName0
) + ';' + Lowercase(HeaderName1
) + ";" + ... + Lowercase(HeaderNameN
)通过对按小写字符代码排序的标头名称集合进行迭代操作,构建已签名标头的列表。对于除最后一个标头外的每个标头名称,请在标头名称后追加分号(“;”),将它与后面的标头名称分隔开。
例 已签名标头
content-type;host;x-amz-date\n
-
使用 SHA256 等哈希 (摘要) 函数以基于 HTTP 或 HTTPS 请求正文中的负载创建哈希值。签名版本 4 不需要您使用特定字符编码来对负载中的文本进行编码。不过,一些 AWS 服务可能需要特定编码。有关更多信息,请参阅该服务的文档。
例 负载结构
HashedPayload = Lowercase(HexEncode(Hash(
requestPayload
)))在创建待签字符串后,请指定用于对负载进行哈希处理的签名算法。例如,如果您使用的是 SHA256,则将指定 AWS4-HMAC-SHA256 作为签名算法。经过哈希处理的负载必须以小写十六进制字符串形式表示。
如果负载为空,则使用空字符串作为哈希函数的输入。在此 IAM 示例中,负载为空。
例 经过哈希处理的负载(空字符串)
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
-
要构建完整的规范请求,请将来自每个步骤的所有组成部分组合为单个字符串。如上所述,每个组成部分都以换行符结尾。如果您执行前述规范请求伪代码,生成的规范请求将显示在以下示例中。
例 规范请求
GET / Action=ListUsers&Version=2010-05-08 content-type:application/x-www-form-urlencoded; charset=utf-8 host:iam.amazonaws.com x-amz-date:20150830T123600Z content-type;host;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
-
使用您对负载进行哈希处理时所使用的相同算法来创建规范请求的摘要(哈希)。
注意 在计算摘要之前,签名版本 4 不需要您使用特定字符编码来对规范请求进行编码。不过,一些 AWS 服务可能需要特定编码。有关更多信息,请参阅该服务的文档。
经过哈希处理的规范请求必须以小写十六进制字符串形式表示。以下示例显示了使用 SHA-256 对示例规范请求进行哈希处理的结果。
例 经过哈希处理的规范请求
f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59
在任务 2:创建签名版本 4 的待签字符串中,将经过哈希处理的规范请求包括到待签字符串中。