本节介绍使用AWS签名版本4算法的请求身份验证。

注意:
如果使用AWS软件开发工具包发送请求,则无需阅读本部分,因为SDK客户端使用您提供的访问密钥验证请求。只有在自定义客户端中实施AWS签名版本4算法时,您才需要阅读本部分。目前MSS同时支持v2和v4二种策略。

签名方法

您可以使用以下方法之一来添加身份签名信息:
HTTP头部签名 - 使用HTTP签名头部是认证MSS请求的最常用方法。
HTTP预签名 - 您可以使用查询字符串在URL中添加签名信息。因为请求签名是URL的一部分,所以这种类型的URL通常被称为预先签名的URL。您可以使用预先分配的网址在HTML中嵌入可点击的链接,该链接最长可以有效七天。
注意:
目前MSS不支持基于HTTP POST请求的v4签名认证。

HTTP头部签名

以下是基于HTTP头部签名方式的请求的Authorization标头值的示例。 为了便于阅读,在此示例中添加换行符:

Authorization: AWS4-HMAC-SHA256 
Credential=AKIAIOSFODNN7EXAMPLE/20161208/US/s3/aws4_request,
SignedHeaders=host;range;x-amz-date,
Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
注意:
AWS4-HMAC-SHA256和Credential之间存在一个空格
Credential,SignedHeaders和Signature由逗号分隔。

下表描述了上例中的各字段的说明:

名称 描述
AWS4-HMAC-SHA256

用于计算签名的算法。 当您使用AWS签名版本4进行身份验证时,必须提供此值。

该字符串指定AWS签名版本4(AWS4)和签名算法(HMAC-SHA256)。

Credential

您的访问密钥和地域信息,包括用于计算签名的日期,区域等信息。

此字符串具有以下形式:

 

<your-access-key>/<date>/<aws-region>/s3/aws4_request

Where:

 

  • <date> value is specified using YYYYMMDD format.

  • <aws-region> 主要用于后端记录用户的地域信息,目前未限定具体值

SignedHeaders 以分号分隔的请求标头列表,用于计算Signature。 该列表仅包括头名称,并且头名称必须为小写。 例如:host;range;x-amz-date
Signature

 它表示为64个小写十六进制字符的256位签名. 例如:

fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024


签名计算因您选择传输请求有效内容的方法而异。 目前mss只支持单个块内容上传。
S3支持以下选项:
传输内容校验:您可以选择计算整个有效负载校验和,并将其包括在签名计算中。 这提供了增加的安全性,但你需要读取你的有效载荷两次或缓冲在内存中。例如,为了上传文件,您需要首先读取文件以计算用于签名计算的有效负载哈希,并在创建请求时再次传输。 对于较小的有效载荷,这种方法可能更可取。 但是,对于大文件,读取文件两次可能效率较低。我们建议您包括有效负载校验和以增加安全性。
传输内容不校验-:不包括签名计算中的有效负载校验和。
注意:
目前MSS暂不支持aws 的 multiple chunks内容校验模式, 采用上面二种方式都需要添加x-amz-content-sha256H,将标头值设置为有效负载校验和(开启传输内容校验选项),或将值设置为文本字符串UNSIGNED-PAYLOAD(传输内容不校验)。

如何计算签名

如图所示签名的过程包括如下几步:
1.规范化请求
2.生成待签名字符串
3.签名
 
下表描述了图中显示的功能。 您需要实现这些功能的代码。
 
函数 描述
Lowercase() 将字符转换为小写
Hex() 十六进制编码
SHA256Hash() 安全散列算法(SHA)加密散列函数。
HMAC-SHA256() 通过使用提供了签名密钥的SHA256算法来计算HMAC。 这是最终的签名。
Trim() 删除任何前导或尾随空格。
UriEncode()

对每个字节进行URI编码。 UriEncode()必须强制执行以下规则:

  • 对非保留字符外的每个字符进行编码,非保留字符包括:'A' - 'Z','a' - 'z','0' - '9',' - ','。','_'和’〜’。
  • 空格字符是保留字符,必须编码为“%20”(而不是“+”)。
  • 每个URI编码字节由“%”和字节的两位十六进制值组成。
  • 十六进制值中的字母必须为大写,例如“%1A”。
  • 在除了对象键名称以外的任何地方编码正斜杠字符'/'。 例如,如果对象键名称为photos/Jan/sample.jpg,则键名称中的正斜杠不会被编码。

 注意

由于RFC中的实现和相关歧义的差异,您的开发平台提供的标准UriEncode函数可能无法工作。 我们建议您编写自己的自定义UriEncode函数,以确保您的编码将工作。以下是Java中的一个示例uri-encode()函数。

public static String UriEncode(CharSequence input, boolean encodeSlash) {           <br />    StringBuilder result = new StringBuilder();           <br />    for (int i = 0; i &lt; input.length(); i++) {               <br />        char ch = input.charAt(i);               <br />        if ((ch &gt;= 'A' &amp;&amp; ch &lt;= 'Z') || (ch &gt;= 'a' &amp;&amp; ch &lt;= 'z') || <br />        (ch &gt;= '0' &amp;&amp; ch &lt;= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {   <br />            result.append(ch);               <br />        } else if (ch == '/') {                   <br />            result.append(encodeSlash ? "%2F" : ch);               <br />        } else {                   <br />            result.append(toHexUTF8(ch));               <br />        }           <br />    }           <br />    return result.toString();       <br />}

规范化请求

本节提供了创建规范请求的概述。
 
以下是Amazon S3用于计算签名的规范请求格式。 要使签名匹配,您必须使用以下格式创建规范请求:

<HTTPMethod>
<CanonicalURI>
<CanonicalQueryString>
<CanonicalHeaders>
<SignedHeaders>
<HashedPayload>

HTTPMethod是其中一种HTTP方法,例如GET,PUT,HEAD和DELETE。
CanonicalURI是URI的绝对路径组件的URI编码版本 - 以域名后面的“/”开头,直到字符串的末尾或以问号字符('?')开头的所有内容 查询字符串参数。 以下示例中的URI /examplebucket/myphoto.jpg是绝对路径,并且不在绝对路径中对“/”进行编码:
http://mtmss.com/examplebucket/myphoto.jpg

CanonicalQueryString指定URI编码的查询字符串参数。 您分别对URI和URI进行编码。 您还必须按键名称按字母顺序对规范查询字符串中的参数进行排序。 编码后进行排序。 以下URI示例中的查询字符串为:
prefix=somePrefix&marker=someMarker:
http://mtmss.com/examplebucket?prefix=somePrefix&marker=someMarker

规范查询字符串如下(为了便于阅读,在此示例中添加换行符):
URI-encode("marker")+"="+URI-encode("someMarker")+"&"+
URI-encode("prefix")+"="+URI-encode(“somePrefix")

当请求针对子资源时,相应的查询参数值将为空字符串(“”)。 例如,以下URI标识examplebucket存储桶上的ACL子资源:
在这种情况下,CanonicalQueryString如下:
URI-encode("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 header。
    您计划要包含在请求中的任何x-amz- *标头也必须添加。
 
下面是一个CanonicalHeaders字符串示例。 标题名称以小写字母排序。
host:mtmss.com
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date:20130708T220855Z

SignedHeaders是按字母顺序排序的,以分号分隔的小写请求标题名称列表。 列表中的请求标头与您在CanonicalHeaders字符串中包含的标头相同。 例如,对于前面的示例,SignedHeaders的值如下:
host;x-amz-content-sha256;x-amz-date

HashedPayload是请求有效内容的SHA256散列的十六进制值。
Hex(SHA256Hash(<payload>)

如果请求中没有有效内容,则计算空字符串的哈希值,如下所示:
Hex(SHA256Hash(“”))

该哈希值返回以下值:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  

例如,当您通过使用PUT请求上传对象时,您在主体中提供对象数据。 当您通过使用GET请求检索对象时,将计算空字符串散列。

生成待签名字符串

本节提供了创建要签名的字符串的概述。
 
要签名的字符串是以下字符串的合并:
"AWS4-HMAC-SHA256" + "\n" +
timeStampISO8601Format + "\n" +
<Scope> + "\n" +
Hex(SHA256Hash(<CanonicalRequest>))

常量字符串AWS4-HMAC-SHA256指定您正在使用的哈希算法HMAC-SHA256。 timeStamp是ISO 8601格式的当前UTC时间(例如,20130524T000000Z)。
Scope 包含特定日期,A区域和服务。 因此,您的结果签名将仅在特定区域和特定服务中工作。 签名在指定日期后的七天内有效。
date.Format(<YYYYMMDD>) + "/" + <region> + "/" + <service> + “/aws4_request"

region用于指定存储的机房区域,目前该指定没有特殊要求
serverice 字段值为s3
如下实例:
20130606/northchina-1/s3/aws4_request

计算签名

在AWS签名版本4中,您不是直接使用MSS ACCESS KEY来签署请求,而是首先基于MSS ACCESS KEY创建一个范围限于特定区域和服务的签名密钥。
DateKey              = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>")
DateRegionKey        = HMAC-SHA256(<DateKey>, "<aws-region>")
DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>")
SigningKey           = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")

通过使用签名密钥,您可以将MSS凭据保存在一个安全的位置。 例如,如果您有多个与MSS通信的服务器,则会与这些服务器共享签名密钥; 您不必在每个服务器上保留您的秘密访问密钥的副本。 签名密钥最多有效期为7天。 因此,每次计算签名密钥时,您都需要与服务器共享签名密钥。
最终签名是要签名的字符串的HMAC-SHA256散列,使用签名密钥作为密钥。
HMAC-SHA256(SigningKey, StringToSign)

示例:签名计算

您可以使用本节中的示例作为检查代码中签名计算的参考。 示例中所示的计算使用以下数据:

示例账号信息

Parameter Value
AWSAccessKeyId AKIAIOSFODNN7EXAMPLE
AWSSecretAccessKey wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

请求的 timestamp of 20130524T000000Z (Fri, 24 May 2013 00:00:00 GMT).
桶名examplebucket.
假设bucket所在的region是beijing
您可以使用路径样式或桶的子域名样式。 以下示例显示如何签名路径样式请求,例如:

Example: GET Object

以下示例从examplebucket获取对象(test.txt)的前10个字节。 有关API操作的更多信息,请参阅GET对象。
GET /examplebucket/test.txt HTTP/1.1
Host: mtmss.com
x-amz-date:20130524T000000Z
Authorization: SignatureToBeCalculated
Range: bytes=0-9 
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date: 20130524T000000Z 

因为此GET请求不提供任何正文内容,所以x-amz-content-sha256值是空请求正文的哈希值。 以下步骤显示了签名计算和授权头的构造。

生成待签名字符串

规范化请求    
GET
/examplebucket/test.txt

host:mtmss.com
range:bytes=0-9
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date:20130524T000000Z

host;range;x-amz-content-sha256;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 

在规范请求字符串中,最后一行是空请求主体的哈希。 第三行为空,因为请求中没有查询参数。

生成待签名字符串

AWS4-HMAC-SHA256
20130524T000000Z
20130524/beijing/s3/aws4_request
7344ae5b7ee6c3e7e6b0fe0640412a37625d1fbfff95c48bbb2dc43964946972

生成签名秘钥

signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request”) 

签名

f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41

生成认证头部

AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;range;x-amz-content-sha256;x-amz-date,Signature=f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41

Presign签名

您可以使用查询字符串参数提供身份验证信息。 当您想在URL中完全表达请求时,使用查询参数来验证请求很有用。 此方法也称为预指定URL。
 
presign URL的用例场景是您可以授予对MSS资源的临时访问权限。 例如,您可以在网站上嵌入预先分配的URL,或者在命令行客户端(如Curl)中使用它来下载对象。
以下是presign示例。
https://mtmss.com/examplebucket/test.txt
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=<your-access-key-id>/20130721/beijing/s3/aws4_request
&X-Amz-Date=20130721T201207Z
&X-Amz-Expires=86400
&X-Amz-SignedHeaders=host
&X-Amz-Signature=<signature-value>  

在示例网址中,请注意以下事项:
    添加换行符是为了可读性。
    URL中的X-Amz-Credential值仅显示“/”字符,以便于阅读。 实际上,它应该编码为%2F。 例如:
  • &X-Amz-Credential=<your-access-key-id>%2F20130721%2Fus-east-1%2Fs3%2Faws4_request 
    
    
下表介绍了提供身份验证信息的URL中的查询参数。
参数名 描述
X-Amz-Algorithm

标识AWS签名的版本以及用于计算签名的算法。对于AWS签名版本4,您将此参数值设置为AWS4-HMAC-SHA256。 

X-Amz-Credential

除了您的访问密钥ID之外,此参数还提供签名有效的范围(AWS区域和服务)。 此值必须与在签名计算中使用的范围相匹配,如以下部分所述。 此参数值的一般形式如下:

<your-access-key-id>/<date>/<AWS-region>/<AWS-service>/aws4_request

例如:

AKIAIOSFODNN7EXAMPLE/20130721/beijing/s3/aws4_request

对于MSS,<AWS-service>值为s3。 <AWS-region>值为beijing

X-Amz-Date

 日期和时间格式必须遵循ISO 8601标准,并且必须使用“yyyyMMddTHHmmssZ”格式进行格式化。 例如,如果日期和时间为“08/01/2016 15:32:41.982-700”,则必须首先将其转换为UTC(协调世界时),然后提交为“20160801T083241Z”。

X-Amz-Expires

提供生成的预先分配的URL有效的时间段(以秒为单位)。 例如,86400(24小时)。 此值为整数。 您可以设置的最小值为1,最大值为604800(七天)。

预先分配的网址最长有效期为7天,因为在签名计算中使用的签名密钥最多有效期为7天。

X-Amz-SignedHeaders
  • 列出用于计算签名的头。 签名计算中需要以下标头:

  •  HTTP host header。

  •  您计划要包含在请求中的任何x-amz- *标头也必须添加。

X-Amz-Signature

提供签名以验证您的请求。 此签名必须与MSS计算的签名相匹配; 否则,MSS会拒绝该请求。 例如, 733255ef022bec3f2a8701cd61d4b371f3f28c9f193a1f02279211d48d5193d7

 

签名过程

请参阅授权头的签名计算。 该过程通常是相同的,除了创建CanonicalRequest不同如下:
  • 您不在规范请求中包括有效负载哈希,因为在创建预分配的URL时,您不知道有效负载内容,因为该URL用于上传任意有效负载。 相反,您使用常量字符串UNSIGNED-PAYLOAD。
  • 规范查询字符串必须包括上表中除X-Amz-Signature之外的所有查询参数。
  • 规范报头必须包括HTTP主机头。 如果计划包括任何x-amz- *头,还必须添加这些头以进行签名计算。 您可以选择添加计划在请求中包含的所有其他标头。 为了增加安全性,您应该尽可能多地标记标头。

示例:签名计算

假设你的examplebucket桶中有一个对象test.txt。 您想要通过创建预先分配的URL与其他人共享此对象,持续24小时(86400秒)。
https://mtmss.com/examplebucket/test.txt
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fbeijing%2Fs3%2Faws4_request
&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
&X-Amz-Signature=<signature-value>

以下步骤首先说明签名计算,然后构造预签名的URL。 
您可以使用此示例作为测试用例来验证代码计算的签名; 但是,必须使用相同的存储桶名称,对象键,时间戳和以下示例凭据:

示例账号信息

Parameter Value
AWSAccessKeyId AKIAIOSFODNN7EXAMPLE
AWSSecretAccessKey ****************
 

生成待签名字符串

规范化请求
GET
/test.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
host:examplebucket.s3.amazonaws.com

host
UNSIGNED-PAYLOAD

生成待签名字符串

AWS4-HMAC-SHA256
20130524T000000Z
20130524/us-east-1/s3/aws4_request
3bfa292879f6447bbcda7001decf97f4a54dc650c8942174ae0a9121cf58ad04

生成签名秘钥

signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request")

签名

aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404