概述
Authorization请求头包含以下信息(增加换行是为了方便阅读,实际为空字符串):
Authorization: AWS4-HMAC-SHA256
Credential=2a948fd3f00ba0925806/20180501/region/s3/aws4_request,
SignedHeaders=host;range;x-amz-date,
Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
组成字段说明如下:
字段 描述 AWS4-HMAC-SHA256
用于签名的算法,固定值。 Credential 用户AccessKeyID和范围信息,范围信息包括请求日期、区域、服务、终止字符串aws4_request,格式如下:
AccessKeyID/date/region/service/aws4_request
其中:
date格式为YYYYMMDD。
region:
对于oos api:访问域名为oos-xx.ctyunapi.cn,region为xx。对于统计api:访问域名为oos-xx-mg.ctyunapi.cn,region为xx-mg。
对于操作跟踪api:访问域名为oos-xx-cloudtrail.ctyunapi.cn,region为xx。
对于iam api:访问域名为oos-xx-iam.ctyunapi.cn,region为xx。
各资源池的详细访问域名详见域名(Endpoint)列表。service:
若使用OOS API服务,service为s3。
若使用统计分析服务,service为s3。
若使用操作跟踪服务,service为cloudtrail。
若使用IAM服务,service为sts。SignedHeaders 已签名请求头的列表。该列表只需包含请求头名字,用分号分隔,必须全部小写,并按字符顺序对其进行排序,示例如下:
host;range;x-amz-date。
Signature 计算出的256位签名信息,以64个小写十六进制字符串形式表示。
有两种签名计算方式:
- 签名负载方式 :用户可以选择计算整个负载(即请求体)的checksum,并将其包含在签名计算中。这种方式提高了安全性,但用户需要读取两次负载或将其缓冲在内存中。我们建议用户包含负载checksum以增强安全性。
- 无签名负载方式 :在签名计算中不包括负载的checksum。将值设置为文本字符串UNSIGNED_PAYLOAD,直接作为签名计算。
上述两种方式,都必须携带x-amz-content-sha256请求头,如果选择签名负载方式,请将x-amz-content-sha256请求头的值设置为负载的checksum值,否则将值设置为文本字符串UNSIGNED-PAYLOAD。
签名过程
签名过程如下图所示:
下表描述了图中显示的功能。用户需要为这些函数实现代码。
功能 描述 Lowercase() 将字符串转换为小写。 Hex() 小写16进制编码。 SHA256Hash() 安全散列算法(SHA)加密散列函数。 HMAC-SHA256() 使用签名密钥,根据SHA256算法计算出的签名值。 Trim() 删除任何前导或尾随空格。 UriEncode() URI编码每个字节。UriEncode()必须强制执行以下规则:
除下列字符外,其他字符进行URI编码:'A' - 'Z','a' - 'z','0' - '9',' - ','.','_'和'~'。
空格字符是保留字符,必须编码为“%20”(而不是“+”)。
每个URI编码字节由'%'和两位十六进制值组成。
十六进制值中的字母必须为大写,例如“%1A”。
除了文件名之外,对正斜杠字符'/'进行编码。例如,如果文件名称为 photos/Jan/sample.jpg,则不对名称中的正斜杠进行编码。
说明建议用户编写自己的自定义UriEncode函数,以确保您的编码可以正常工作。
以下是Java中的示例UriEncode()函数。
public static String UriEncode(CharSequence input, boolean encodeSlash) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {
result.append(ch);
} else if (ch == '/') {
result.append(encodeSlash ? "%2F" : ch);
} else {
result.append(toHexUTF8(ch));
}
}
return result.toString();
}
-
创建规范请求
将请求的内容(包括主机、操作、请求头等)组织为标准规范格式。规范请求是用于创建待签字符串的输入之一。伪代码如下:
CanonicalRequest = HTTPRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload))
-
HTTPMethod是HTTP方法,例如GET,PUT,HEAD和DELETE。
-
CanonicalURI是URI的绝对路径,以域名后面的“/”开头,直到字符串的末尾或者问号字符('?')截止。例如/examplebucket/myphoto.jpg。
-
CanonicalQueryString是URI编码后的查询字符串参数。用户需要单独对参数名称和值进行URI编码。并需要按参数名称的字母顺序,对参数进行排序。排序在编码后进行。以下URI示例中的查询字符串是 prefix=somePrefix&marker=someMarker&max-keys=20:
http://oos-cn.ctyunapi.cn/examplebucket?prefix=somePrefix&marker=someMarker&max-keys=20
CanonicalQueryString的构造方式如下(为了便于阅读,添加了换行符):
UriEncode("marker")+"="+UriEncode("someMarker")+"&"+ UriEncode("max-keys")+"="+UriEncode("20") + "&" + UriEncode("prefix")+"="+UriEncode("somePrefix")
当请求的目标是子资源时,相应的查询参数的值设置为空字符串(“”)。例如,下面的请求用于设置Bucket的ACL权限:
http://oos-cn.ctyunapi.cn/examplebucket?acl
在这种情况下,CanonicalQueryString为:
UriEncode("acl") + "=" + ""
如果URI中不包含“?”,则请求中不存在查询字符串,此时将CanonicalQueryString设置为空字符串(“”),但仍需要包含“\ n”。
-
CanonicalHeaders是请求头的列表:
各个请求头名称和值由换行符(“\ n”)分隔。请求头名称必须为小写。如果有相同名字的请求头,则根据标准RFC 2616, 4.2章进行合并(两个值之间只用英文逗号分隔)。如有两个名为'x-amz-meta-name'的请求头,对应的值分别为'fred'和'barney',则合并后为:'x-amz-meta-name:fred,barney'。删除分隔符(:)两端和值两端出现的任何空格。如'x-amz-meta-name : fred '转换成:'x-amz-meta-name:fred'。需要按字母顺序对请求头名称进行排序。
示例如下:Lowercase(Trim(<HeaderName1>))+":"+Trim(<value>)+"\n" Lowercase(Trim(<HeaderName2>))+":"+Trim(<value>)+"\n" ... Lowercase(Trim(<HeaderNameN>))+":"+Trim(<value>)+"\n"
CanonicalHeaders列表必须包括以下内容:HTTP Host标头。如果存在Content-Type请求头,则必须将其添加到CanonicalHeaders列表中。所有x-amz-*请求头,例如,如果您使用的是临时安全凭据,则需要在请求中包含x-amz-security-token,必须将此标题添加到CanonicalHeader列表中。
以下是CanonicalHeaders的示例,请求头名称为小写并已排序。
host:oos-cn.ctyunapi.cn x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130708T220855Z
-
SignedHeaders是按字母顺序排序的,以分号分隔的小写请求头名称列表。列表中的请求头与用户在CanonicalHeaders字符串中包含的请求头相同。例如,对于前面的示例,SignedHeaders的值为:
host;x-amz-content-sha256;x-amz-date
-
RequestPayload是请求负载的SHA256哈希的十六进制值。
如果请求中没有负载,则计算空字符串的哈希值,如下所示: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时间(例如20180501T000000Z)。
Scope是将生成的签名绑定到指定日期,OOS区域和服务。
date.Format(<YYYYMMDD>) + "/" + <region> + "/" + <service> + "/aws4_request"
-
计算签名
使用SecretAccessKey作为初始哈希操作的密钥,对请求日期、区域和服务执行一系列加密哈希操作(HMAC 操作),从而派生签名密钥。伪代码如下:DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>") DateRegionKey = HMAC-SHA256(<DateKey>, "< region>") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<service>") SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")
最终签名是使用签名密钥作为密钥,对待签名字符串计算得到HMAC-SHA256哈希值。伪代码如下:
HMAC-SHA256(SigningKey, StringToSign)
-
将签名信息添加到请求头
在计算签名后,将其添加到请求的HTTP请求头或查询字符串中。
将签名信息添加到Authorization标头的伪代码如下:
Authorization: <algorithm> Credential=<ak>/<credential_scope>, SignedHeaders=<SignedHeaders>, Signature=<signature>
示例
以下是使用V4签名的示例。示例中使用的访问密钥如下:
参数 | 值 |
---|---|
AccessKeyID | 2a948fd3f00ba0925806 |
SecretAccessKey | ef2017c2e5ffa0b1761717ecbca021da16501384 |
Bucket名称:example-bucket。
访问的域名是oos-cn.ctyunapi.cn, region是cn。
示例:GET文件
从存储桶example-bucket中获取文件test.txt的前10个字节。请求如下:
GET /test.txt HTTP/1.1
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Authorization: SignatureToBeCalculated
x-amz-date: 20190220T060724Z
Range: bytes=0-9
Host: example-bucket.oos-cn.ctyunapi.cn
由于此GET请求不提供任何请求体内容,因此该x-amz-content-sha256请求头的值是空请求体的哈希值。以下步骤显示Authorization请求头的计算的方法。
- StringToSign
-
创建规范请求
GET /test.txt host:example-bucket.oos-cn.ctyunapi.cn range:bytes=0-9 x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20190220T060724Z host;range;x-amz-content-sha256;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
其中,最后一行是空请求体的hash值。第三行是空,因为此请求不包含请求参数。
-
待签名字符串
AWS4-HMAC-SHA256 20190220T060724Z 20190220/cn/s3/aws4_request a6417debbe1fe886b8ed84dca872475f7f09b01961af10d30fa601bc0986ba36
-
- 生成签名密钥
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<SecretAccessKey>","20190220"),"cn"),"s3"),"aws4_request")
- 计算后的签名
dcefeb864c1ffad98f8f0307af32ceb584b38dc2a9c7a65459363cdb03fc6f12
- Authorization请求头
Authorization: AWS4-HMAC-SHA256 Credential=2a948fd3f00ba0925806/20190220/cn/s3/aws4_request, SignedHeaders=host;range;x-amz-content-sha256;x-amz-date, Signature=dcefeb864c1ffad98f8f0307af32ceb584b38dc2a9c7a65459363cdb03fc6f12
示例:PUT文件
在存储桶example-bucket中上传文件test.txt。
PUT /test.txt HTTP/1.1
x-amz-content-sha256: 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9
Authorization:SignatureToBeCalculated
x-amz-date: 20190220T070722Z
x-amz-storage-class: STANDARD
Host: example-bucket.oos-cn.ctyunapi.cn
Content-Length: 12
hello world!
以下步骤显示Authorization请求头的计算的方法。
- StringToSign
-
创建规范请求
PUT /test.txt content-length:12 host:example-bucket.oos-cn.ctyunapi.cn x-amz-content-sha256:7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 x-amz-date:20190220T070722Z x-amz-storage-class:STANDARD content-length;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9
其中,第三行是空,因为此请求不包含请求参数。最后一行是请求体的hash值,它必须与x-amz-content-sha256 请求头的值相同。
-
待签名字符串
AWS4-HMAC-SHA256 20190220T070722Z 20190220/cn/s3/aws4_request 013accc1b2460f530908e106224c57d9fcf9ed74986f5399e27196b73824ddf3
-
- 生成签名密钥
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<SecretAccessKey>","20190220"),"cn"),"s3"),"aws4_request")
- 计算后的签名
5c4e3bc9b2589f2d451a7570cb1283637691f95671525fb0223a1fd158f5fee1
- Authorization请求头
Authorization: AWS4-HMAC-SHA256 Credential=2a948fd3f00ba0925806/20190220/cn/s3/aws4_request, SignedHeaders=contentlength;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=5c4e3bc9b2589f2d451a7570cb1283637691f95671525fb0223a1fd158f5fee1
示例:列出存储桶中的文件
列出存储桶example-bucket中的文件,prefix设置为“t”,最多返回2个文件。请求如下:
GET /?max-keys=2&prefix=t HTTP/1.1
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Authorization: SignatureToBeCalculated
x-amz-date: 20190220T085955Z
Host: example-bucket.oos-cn.ctyunapi.cn
以下步骤显示Authorization请求头的计算的方法。
- StringToSign
-
创建规范请求
GET / max-keys=2&prefix=t host:example-bucket.oos-cn.ctyunapi.cn x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20190220T085955Z host;x-amz-content-sha256;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
其中,最后一行是空请求体的hash值。
-
待签名字符串
AWS4-HMAC-SHA256 20190220T085955Z 20190220/cn/s3/aws4_request 3b6553685b6c201cd38cb1077fe657b0f55b355e7ae011e31fa244d009c4d43a
-
- 生成签名密钥
signing key = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" + "<SecretAccessKey>","20190220"),"cn"),"s3"),"aws4_request")
- 计算后的签名
72c3758e3b8f27a1a9d9d38b4c143329d3094bc8156d28581bfdd5b7663d6ca8
- Authorization请求头
Authorization: AWS4-HMAC-SHA256 Credential=2a948fd3f00ba0925806/20190220/cn/s3/aws4_request, SignedHeaders=host;x-amzcontent-sha256;x-amz-date, Signature=72c3758e3b8f27a1a9d9d38b4c143329d3094bc8156d28581bfdd5b7663d6ca8