在Header中包含签名
在Header中包含签名
用户可以在HTTP请求中增加Authorization(授权)的Header来包含签名(Signature)信息,表明这个消息已被授权。
Authorization字段计算的方法
"Authorization: COS " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha256(AccessKeySecret,
VERB + "\n”
+ Content-MD5 + "\n"
+ Content-Type + "\n"
+ Date + "\n"
+ CanonicalizedCOSHeaders
+ CanonicalizedResource))
- AccessKeySecret表示签名所需的秘钥
- VERB表示HTTP请求的Method,主要有PUT,GET,POST,HEAD,DELETE等
- "\n"表示换行符
- Content-MD5表示请求内容数据的MD5值,对消息内容(不包括头部)计算MD5值。该请求头可用于消息合法性的检查(消息内容是否与发送时一致),如果为空则表示不做检查
- Content-Type表示请求内容的类型,如"application/octet-stream",也可以为空
- Date表示此次操作的时间,且必须为HTTP1.1中支持的GMT格式,如"Sun, 22 Nov 2015 08:16:38 GMT"
- CanonicalizedCOSHeaders表示以“x-cos-”为前缀的HTTP Header的组合;
- CanonicalizedResource 表示用户想要访问的COS资源
其中,Date和CanonicalizedResource不能为空;如果请求中的DATE时间和COS服务器的时间差正负15分钟以上,COS服务器将拒绝该服务,并返回HTTP 403错误。
构建CanonicalizedCOSHeaders的方法
所有以"x-cos-"为前缀的HTTP Header被称为CanonicalizedCOSHeaders。它的构建方法如下:
- 将所有以"x-cos-"为前缀的HTTP请求头的名字转换成小写字母。如"X-COS-Meta-Name: Demo"转换成"x-cos-meta-name: Demo"
- 将上一步得到的所有HTTP请求头按照名字的字典序进行升序排列
- 删除请求头和内容之间分隔符两端出现的任何空格。如"x-cos-meta-name: Demo"转换成:"x-cos-meta-name:Demo"
- 将每一个头和内容用"\n"分隔符分隔拼成最后的CanonicalizedCOSHeaders
注意
1. CanonicalizedCOSHeaders可以为空,无需添加最后的"\n"
2. 如果只有一个,则如'x-cos-meta-a\n',注意最后的"\n"
3. 如果有多个,则如‘x-cos-meta-a:a\nx-cos-meta-b:b\nx-cos-meta-c:c\n',注意最后的"\n"
构建CanonicalizedResource的方法
用户发送请求中想访问的COS目标资源被称为CanonicalizedResource。它的构建方法如下:
- 将CanonicalizedResource置成空字符串("")
- 放入要访问的COS资源:"/bucketname/ObjectName"(无ObjectName则CanonicalizedResource为"/bucketname/",如果同时也没有bucketname则为"/")
- 如果请求的资源包括子资源(sub-resource),那么将所有的子资源按照字典序,从小到大排列并以&为分隔符生成资资源字符串。在CanonicalizedResource字符串尾添加”?”和子资源字符串。示例:
/ObjectName?partNumber=PartNumber&uploadId=UploadId
- COS目前支持的子资源(sub-resource)包括:acl,uploadId,partNumber,uploads,website,delete,location
计算签名注意事项
- 签名的字符串必须为UTF-8格式。含有中文字符的签名字符串必须先进行UTF-8编码,再与AccessKeySecret计算最终签名
- 签名的方法用RFC 2104中定义的HMAC-SHA256方法,其中Key为AccessKeySecret
- Content-Type和Content-MD5在请求中不是必须的,但是如果请求需要签名验证,空值的话以换行符“\n”代替
- 在所有非HTTP标准定义的Header中,只有以“x-cos-”开头的header,需要加入签名字符串;其他非HTTP标准header将被COS忽略
- 以“x-cos-”开头的Header在签名验证前需要符合以下规范:
- Header的名字需要变成小写
- Header按字典序自小到大排序
- 分割Header的name和value的冒号前后不能有空格
- 每个Header之后都有一个换行符“\n”,如果没有自定义Header,CanonicalizedCOSHeaders就设置为空
签名示例代码
假定用户想要往名称为mybucket
的桶上传对象MyObject.txt
,用户的密钥对为:
AccessKeyId = "YOUR_ACCESS_KEY_ID"
AccessKeySecret = "YOUR_ACCESS_KEY_SECRET"
那么,尚未加入Header签名Authorization的请求头为:
PUT /MyObject.txt HTTP/1.1
Host: mybucket.cos-cn-suzhou.chinac.com
Content-MD5: SDBGOERFM¥GDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=
Content-Type: text/plain
Date: Fri, 14 Nov 2015 19:47:08 GMT
X-COS-Meta-Author: my@gmail.com
X-COS-Magic: Chinac
通过Authorization字段计算的方法,以及CanonicalizedCOSHeaders和CanonicalizedResource构建方法,计算出签名Signature:
#! /usr/bin/python
import base64
import hmac
import hashlib
h = hmac.new(
"YOUR_ACCESS_KEY_SECRET",
"PUT\n" + # HTTP-VERB
"ODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\n" + # Content-MD5
"text/plain\n" + # Content-Type
"Fri, 14 Nov 2015 19:47:08 GMT\n" + # Date
"x-cos-magic:Chinac\n" + # CanonicalizedHeaders
"x-cos-meta-author:my@gmail.com\n" +
"/mybucket/MyObject", # CanonicalizedResource, MyObject need urlencode
hashlib.sha256)
print "Signature is " + base64.b64encode(h.digest())
# OUTPUT: Signature is fP7/XUUN6+8UmHJ9d9YGo8dpuRPeYlv3wX72A+kKM/A=
至此,根据Authorization头组成方式Authorization: COS " + AccessKeyId + ":" + Signature
,能够拼接出最终的HTTP请求头,如下:
PUT /MyObject.txt HTTP/1.1
Host: mybucket.cos-cn-suzhou.chinac.com
Content-MD5: SDBGOERFM¥GDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=
Content-Type: text/plain
Date: Fri, 14 Nov 2015 19:47:08 GMT
X-COS-Meta-Author: my@gmail.com
X-COS-Magic: Chinac
Authorization: COS dcbf4036e50a4135aaab604f729a8115:fP7/XUUN6+8UmHJ9d9YGo8dpuRPeYlv3wX72A+kKM/A=
细节说明
- 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId
- 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument
- COS所有的请求都必须使用HTTP1.1协议规定的GMT时间格式,错误的时间格式将返回失败
- 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied
- 传入请求的时间必须在COS服务器当前时间之后的15分钟以内,否则返回403Forbidden。错误码:RequestTimeTooSkewed
- 如果AccessKeyId是active的,但COS判断用户的请求发生签名错误,则返回403Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串
常见问题
Content-MD5的计算方法
以消息内容为"123456789"来说,计算这个字符串的Content-MD5
正确的计算方式,以Python为例子:
>>> import hashlib
>>> hash = hashlib.md5()
>>> hash.update("0123456789")
>>> hash.hexdigest()
'781e5e245d69b566979b86e28d23f2c7'