Authorization 标头的签名计算:在单个分块中传输有效载荷(Amazon 签名版本 4)
使用 Authorization 标头对请求进行身份验证时,标头值包括签名等其它内容。签名计算因您就传输有效载荷所进行的选择而异(概述)。本节介绍在选择以单个分块传输有效载荷时的签名计算。示例部分(请参阅示例:签名计算)显示了签名计算和生成的 Authorization 标头,您可以将其用作测试套件来验证代码。
重要
在单个分块中传输有效载荷时,您可以选择在签名计算中包含有效载荷哈希值,称为已签名的有效载荷(如果不包括该哈希值,则该有效载荷被视为未签名)。下一节中讨论的签名过程适用于这两者,但请注意以下区别:
-
签名的有效载荷选项:在构造规范请求时包含有效载荷哈希值(然后,该哈希值将成为 StringToSign 的一部分,如签名计算部分所述)。在向 S3 发送请求时,您还可以指定与
x-amz-content-sha256标头值相同的值。 -
未签名的有效载荷选项:您在构造规范请求时包含文本字符串
UNSIGNED-PAYLOAD,并在向 Amazon S3 发送请求时设置与x-amz-content-sha256标头值相同的值。
当您将请求发送到 Amazon S3 时,x-amz-content-sha256 标头值会通知 Amazon S3 有效载荷是否已签名。然后,Amazon S3 可以相应地创建签名以进行验证。
在这两种情况下,由于 x-amz-content-sha256 标头值已经是 HashedPayload 的一部分,因此您无需将 x-amz-content-sha256 标头作为规范标头包含在内。
计算签名
要计算签名,首先需要一个待签字符串。然后,使用签名密钥计算待签字符串的 HMAC-SHA256 哈希值。下图演示了该过程,包括您为签名而创建的字符串的各个组成部分
Amazon S3 收到经身份验证的请求时,它将计算签名,然后将其与您在请求中提供的签名进行比较。出于此原因,您必须采用 Amazon S3 使用的相同方法来计算签名。根据适用于签名的统一格式放置请求的过程称为标准化。
下表介绍了图中显示的函数。您需要为这些函数实现代码。
| 函数 | 说明 |
|---|---|
Lowercase() |
将字符串转换为小写。 |
Hex() |
base-16 编码的小写形式。 |
SHA256Hash() |
安全哈希算法(SHA)加密哈希函数。 |
HMAC-SHA256() |
使用 SHA256 算法和提供的签名密钥计算 HMAC。这是最终的签名。 |
Trim() |
删除所有前导空格或尾随空格。 |
UriEncode() |
URI 对每个字节进行编码。UriEncode() 必须强制执行以下规则:
重要由于底层 RFC 中的实现差异和相关歧义,您开发平台提供的标准 UrienCode 函数可能无法正常工作。建议您编写自己的自定义 UrienCode 函数,以确保编码能够正常工作。 以下是 Java 中的 UriEncode() 函数示例。
|
任务 1:创建规范请求
本节提供创建规范请求的概述。
以下是 Amazon S3 用来计算签名的规范请求格式。要使签名匹配,您必须使用以下格式创建规范请求:
<HTTPMethod>\n<CanonicalURI>\n<CanonicalQueryString>\n<CanonicalHeaders>\n<SignedHeaders>\n<HashedPayload>
其中:
-
HTTPMethod是 HTTP 方法之一,例如 GET、PUT、HEAD 和 DELETE。 -
CanonicalURI是 URI 的绝对路径组件的 URI 编码版本,即从域名后面的“/”开始,直至字符串结尾处的任何内容;或者如果包含查询字符串参数,则为直至问号字符(“?”)的任何内容。以下示例中的 URI/examplebucket/myphoto.jpg是绝对路径,并且您无需在绝对路径中对“/”进行编码:http://s3.amazonaws.com/examplebucket/myphoto.jpg注意
向 Amazon S3 发出请求时,您没有对 URI 路径进行规范化。例如,您可能有一个存储桶,其中包含一个名为“my-object//example//photo.user”的对象。对路径进行规范化会将请求中的对象名称更改为“my-object/example/photo.user”。这是该对象的不正确路径。
-
CanonicalQueryString指定 URI 编码的查询字符串参数。您可以单独对名称和值进行 URI 编码。您还必须按键名称的字母顺序对规范查询字符串中的参数进行排序。编码后进行排序。以下 URI 示例中的查询字符串是:prefix=somePrefix&marker=someMarker&max-keys=20http://s3.amazonaws.com/examplebucket?prefix=somePrefix&marker=someMarker&max-keys=20规范查询字符串如下所示(为便于阅读,此示例中添加了换行符:):
UriEncode("marker")+"="+UriEncode("someMarker")+"&"+ UriEncode("max-keys")+"="+UriEncode("20") + "&" + UriEncode("prefix")+"="+UriEncode("somePrefix")当请求针对子资源时,相应的查询参数值将为空字符串(“”)。例如,以下 URI 标识了
examplebucket存储桶上的ACL子资源:http://s3.amazonaws.com/examplebucket?acl本例中的 CanonicalQueryString 如下:
UriEncode("acl") + "=" + ""如果 URI 不包含“?”,则请求中没有查询字符串,并且您需要将规范查询字符串设置为空字符串(“”)。此外,仍需包含“\n”。
-
CanonicalHeaders是请求标头及其值的列表。各个标头名称和值对用换行符(“\n”)分隔。标头名称必须为小写。您必须按字母顺序对标头名称进行排序才能构造字符串,如以下示例所示:Lowercase(<HeaderName1>)+":"+Trim(<value>)+"\n" Lowercase(<HeaderName2>)+":"+Trim(<value>)+"\n" ... Lowercase(<HeaderNameN>)+":"+Trim(<value>)+"\n"上一部分介绍了本示例中使用的
Lowercase()和Trim()函数。CanonicalHeaders列表必须包含以下内容:-
HTTP
host标头。 -
如果请求中存在
Content-MD5标头,则必须将其添加到CanonicalHeaders列表中。 -
此外,还必须添加计划在请求中包含的所有
x-amz-*标头。例如,如果您使用临时安全凭证,则请求中必须包含x-amz-security-token。您必须将此标头添加到CanonicalHeaders列表中。
注意
所有 Amazon 签名版本 4 请求都需要
x-amz-content-sha256标头。它将提供请求负载的哈希。但是,您无需将x-amz-content-sha256作为规范标头包含在内,因为 S3 在计算请求中发送的有效载荷哈希值时会自动使用其值。如果不包含有效负载,则必须提供空字符串的哈希值。
如果您不希望 S3 检查请求的哈希值,则可以改用文本字符串
"UNSIGNED-PAYLOAD"。
以下是示例
CanonicalHeaders字符串。标头名称为小写且已排序。例示例 1
host:s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130708T220855Z例示例 2
host:s3.amazonaws.com x-amz-content-sha256:UNSIGNED-PAYLOAD x-amz-date:20130708T220855Z例示例 3
host:s3.amazonaws.com x-amz-date:20130708T220855Z注意
为了计算授权签名,需要主机标头和所有
x-amz-*标头(不包括x-amz-content-sha256)。但是,为了防止篡改数据,您应该考虑在签名计算中包含所有标头。对
x-amz-content-sha256标头进行签名是可选的,因为 S3 将在计算收到的请求有效载荷哈希值时使用其值。 -
-
SignedHeaders是按字母顺序排序、以分号分隔的小写请求标头名称的列表。列表中的请求标头与您在CanonicalHeaders字符串中包含的标头相同。在前面的示例中,SignedHeaders的值如下:例示例 1 和 2
host;x-amz-content-sha256;x-amz-date例示例 3
host;x-amz-date -
HashedPayload是请求有效载荷的 SHA256 哈希值的十六进制值。Hex(SHA256Hash(<payload>)如果请求中不包含有效负载,则按如下方式计算空字符串的哈希值:
Hex(SHA256Hash(""))哈希值将返回以下值:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855例如,当您使用 PUT 请求上传对象时,您需要在正文中提供对象数据。当您使用 GET 请求检索对象时,您将计算空字符串哈希值。
任务 2:创建待签字符串
本节提供创建待签字符串的概述。有关分步说明,请参阅《Amazon Web Services 一般参考》中的任务 2:创建待签字符串。
待签字符串是以下字符串的结合:
"AWS4-HMAC-SHA256" + "\n" + timeStampISO8601Format + "\n" +<Scope>+ "\n" + Hex(SHA256Hash(<CanonicalRequest>))
常量字符串 AWS4-HMAC-SHA256 指定您正在使用的哈希算法 HMAC-SHA256。timeStamp 是采用 ISO 8601 格式的当前 UTC 时间(例如 20130524T000000Z)。
Scope 将生成的签名绑定到特定的日期、Amazon Web Services 区域和服务。这样,生成的签名将仅在特定区域和特定服务中有效。签名在指定日期后的七天内有效。
date.Format(<YYYYMMDD>) + "/" +<region>+ "/" +<service>+ "/aws4_request"
对于 Amazon S3,服务字符串为 s3。有关 region 字符串的列表,请参阅《Amazon Web Services 一般参考》中的区域和端点。此表中的“区域”列提供了有效区域字符串的列表。
以下范围将生成的签名限制为 us-east-1 区域和 Amazon S3。
20130606/us-east-1/s3/aws4_request
注意
Scope 必须使用与用于计算签名密钥的相同日期,如下一节所述。
任务 3:计算签名
在 Amazon 签名版本 4 中,您首先创建一个范围仅限于特定区域和服务的签名密钥,而不是使用 Amazon 访问密钥对请求进行签名。 有关签名密钥的更多信息,请参阅对请求进行签名简介。
DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>") DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>") SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")
注意
一些使用案例可以处理签名密钥长达 7 天。有关更多信息,请参阅与他人共享对象。
有关区域字符串的列表,请参阅《Amazon Web Services 一般参考》中的区域和端点。
使用签名密钥,您可以将 Amazon 凭证保存在一个安全的地方。例如,如果您有多个服务器与 Amazon S3 通信,则可以与这些服务器共享签名密钥;您不必在每个服务器上保留秘密访问密钥的副本。签名密钥的有效期最长为七天。因此,每次计算签名密钥时,都需要与服务器共享签名密钥。有关更多信息,请参阅 对请求进行身份验证(Amazon 签名版本 4)。
最终签名是待签字符串的 HMAC-SHA256 哈希值,使用签名密钥作为密钥。
HMAC-SHA256(SigningKey, StringToSign)
有关创建签名的分步说明,请参阅《Amazon Web Services 一般参考》中的任务 3:创建签名。
示例:签名计算
您可以将本节中的示例用作参考,以检查代码中的签名计算。示例中显示的计算使用以下数据:
-
访问密钥示例。
参数 值 AWSAccessKeyIdAKIAIOSFODNN7EXAMPLEAWSSecretAccessKeywJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY -
请求时间戳:20130524T000000Z (
Fri, 24 May 2013 00:00:00 GMT)。 -
存储桶名称
examplebucket。 -
假设存储桶位于美国东部(弗吉尼亚州北部)区域。凭证
Scope和Signing Key计算使用us-east-1作为区域说明符。有关其它区域的信息,请参阅《Amazon Web Services 一般参考》中的区域和端点。 -
您可以使用路径类型请求或虚拟托管类型请求。以下示例演示如何对虚拟托管类型请求进行签名,例如:
https://examplebucket.s3.amazonaws.com/photos/photo1.jpg有关更多信息,请参阅《Amazon Simple Storage Service 用户指南》中的存储桶的虚拟托管。
示例:GET 对象
以下示例从 examplebucket 获取对象(test.txt)的前 10 个字节。有关 API 操作的更多信息,请参阅 GetObject。
GET /test.txt HTTP/1.1 Host: examplebucket.s3.amazonaws.com Authorization:SignatureToBeCalculatedRange: bytes=0-9 x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date: 20130524T000000Z
由于此 GET 请求不提供任何正文内容,因此 x-amz-content-sha256 值可以是空请求正文的哈希值,也可以是文本字符串 "UNSIGNED-PAYLOAD"。以下步骤显示使用空字符串的哈希值进行签名计算以及构造 Authorization 标头的过程。
-
StringToSign
-
CanonicalRequest
GET /test.txt host:examplebucket.s3.amazonaws.com range:bytes=0-9 x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130524T000000Z host;range;x-amz-content-sha256;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855在规范请求字符串中,最后一行是空请求正文的哈希值。因为请求中没有查询参数,所以第三行是空的。
-
StringToSign
AWS4-HMAC-SHA256 20130524T000000Z 20130524/us-east-1/s3/aws4_request 7344ae5b7ee6c3e7e6b0fe0640412a37625d1fbfff95c48bbb2dc43964946972
-
-
SigningKey
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request") -
Signature
f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41 -
Authorization 标头
生成的
Authorization标头如下:AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;range;x-amz-content-sha256;x-amz-date,Signature=f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41
示例:PUT 对象
此示例 PUT 请求在 examplebucket 中创建一个对象 (test$file.text)。示例假定以下各项:
-
您正在通过添加
x-amz-storage-class请求标头来请求REDUCED_REDUNDANCY作为存储类别。有关存储类别的信息,请参阅《Amazon Simple Storage Service 用户指南》中的存储类别。 -
已上传文件的内容是一个字符串
"Welcome to Amazon S3.",请求中x-amz-content-sha256的值基于这个字符串。
有关 API 操作的信息,请参阅 PutObject。
PUT test$file.text HTTP/1.1 Host: examplebucket.s3.amazonaws.com Date: Fri, 24 May 2013 00:00:00 GMT Authorization:SignatureToBeCalculatedx-amz-date: 20130524T000000Z x-amz-storage-class: REDUCED_REDUNDANCY x-amz-content-sha256: 44ce7dd67c959e0d3524ffac1771dfbba87d2b6b4b4e99e42034a8b803f8b072<Payload>
以下步骤显示了签名计算。
-
StringToSign
-
CanonicalRequest
PUT /test%24file.text date:Fri, 24 May 2013 00:00:00 GMT host:examplebucket.s3.amazonaws.com x-amz-content-sha256:44ce7dd67c959e0d3524ffac1771dfbba87d2b6b4b4e99e42034a8b803f8b072 x-amz-date:20130524T000000Z x-amz-storage-class:REDUCED_REDUNDANCY date;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class 44ce7dd67c959e0d3524ffac1771dfbba87d2b6b4b4e99e42034a8b803f8b072在规范请求中,第三行是空的,因为请求中没有查询参数。可以选择对
x-amz-content-sha256规范标头进行签名,因为其有效载荷哈希值已在请求的底部提供。最后一行是正文的哈希值,它应该与在 HTTP 请求中发送给 S3 的x-amz-content-sha256 header值相同。 -
StringToSign
AWS4-HMAC-SHA256 20130524T000000Z 20130524/us-east-1/s3/aws4_request 9e0e90d9c76de8fa5b200d8c849cd5b8dc7a3be3951ddb7f6a76b4158342019d
-
-
SigningKey
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request") -
Signature
98ad721746da40c64f1a55b78f14c238d841ea1380cd77a1b5971af0ece108bd -
Authorization 标头
生成的
Authorization标头如下:AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=date;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class,Signature=98ad721746da40c64f1a55b78f14c238d841ea1380cd77a1b5971af0ece108bd
示例:GET 存储桶生命周期
以下 GET 请求检索 examplebucket 的生命周期配置。有关 API 操作的信息,请参阅 GetBucketLifecycleConfiguration。
GET ?lifecycle HTTP/1.1 Host: examplebucket.s3.amazonaws.com Authorization:SignatureToBeCalculatedx-amz-date: 20130524T000000Z x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
由于请求未提供任何正文内容,因此 x-amz-content-sha256 标头值是空请求正文的哈希值。以下步骤显示了签名计算。
-
StringToSign
-
CanonicalRequest
GET / lifecycle= host:examplebucket.s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130524T000000Z host;x-amz-content-sha256;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855在规范请求中,最后一行是空请求正文的哈希值。
-
StringToSign
AWS4-HMAC-SHA256 20130524T000000Z 20130524/us-east-1/s3/aws4_request 9766c798316ff2757b517bc739a67f6213b4ab36dd5da2f94eaebf79c77395ca
-
-
SigningKey
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request") -
Signature
fea454ca298b7da1c68078a5d1bdbfbbe0d65c699e0f91ac7a200a0136783543 -
Authorization 标头
生成的
Authorization标头如下:AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=fea454ca298b7da1c68078a5d1bdbfbbe0d65c699e0f91ac7a200a0136783543
示例:Get 存储桶(列出对象)
以下示例从 examplebucket 存储桶中检索对象的列表。有关 API 操作的信息,请参阅 ListObjects。
GET ?max-keys=2&prefix=J HTTP/1.1 Host: examplebucket.s3.amazonaws.com Authorization:SignatureToBeCalculatedx-amz-date: 20130524T000000Z x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
由于请求未提供正文,因此 x-amz-content-sha256 的值是空请求正文的哈希值。以下步骤显示了签名计算。
-
StringToSign
-
CanonicalRequest
GET / max-keys=2&prefix=J host:examplebucket.s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130524T000000Z host;x-amz-content-sha256;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855在规范请求中,最后一行是空请求正文的哈希值。
-
StringToSign
AWS4-HMAC-SHA256 20130524T000000Z 20130524/us-east-1/s3/aws4_request df57d21db20da04d7fa30298dd4488ba3a2b47ca3a489c74750e0f1e7df1b9b7
-
-
SigningKey
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request") -
Signature
34b48302e7b5fa45bde8084f4b7868a86f0a534bc59db6670ed5711ef69dc6f7 -
Authorization 标头
生成的
Authorization标头如下:AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=34b48302e7b5fa45bde8084f4b7868a86f0a534bc59db6670ed5711ef69dc6f7