您可以在HTTP请求中增加Authorization
的Header来包含签名(Signature)信息,表明该消息已被授权。
SDK签名实现
SDK | 签名实现 |
---|---|
Java SDK | OSSRequestSigner.java |
Python SDK | auth.py |
.Net SDK | OssRequestSigner.cs |
PHP SDK | OssClient.php |
C SDK | oss_auth.c |
JavaScript SDK | client.js |
Go SDK | auth.go |
Ruby SDK | util.rb |
iOS SDK | OSSModel.m |
Android SDK | OSSUtils.java |
当您自己实现签名,访问OSS报SignatureDoesNotMatch
错误时,请参见自签名计算失败排除错误。
Authorization字段计算的方法
- 计算方法
Authorization = "OSS " + AccessKeyId + ":" + Signature Signature = base64(hmac-sha1(AccessKeySecret, VERB + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedOSSHeaders + CanonicalizedResource))
- 参数
参数 是否必选 示例值 说明 AccessKeySecret 是 OtxrzxIsfpFjA7Sw******8Bw21TLhquhboDYROV 签名所需的密钥。 VERB 是 PUT HTTP请求的Method,主要有PUT、GET、POST、HEAD、DELETE等。 \n 否 \n 换行符。 Content-MD5 否 eB5eJF1ptWaXm4bijSPyxw== 请求内容数据的MD5值,对消息内容(不包括头部)计算MD5值获得128比特位数字,对该数字进行base64编码得出。更多信息,请参见RFC2616 Content-MD5。 该请求头可用于消息合法性的检查(消息内容是否与发送时一致),也可以为空。
关于Content-MD5的计算方法,请参见Content-MD5的计算方法。
Content-Type 否 application/octet-stream 请求内容的类型,也可以为空。 Date 是 Sun, 22 Nov 2015 08:16:38 GMT 此次操作的时间,Date必须为GMT格式且不能为空。 注意 如果请求中的Date时间和OSS服务器的当前时间差15分钟以上,OSS服务器将拒绝该请求,并返回HTTP 403错误。CanonicalizedOSSHeaders 否 x-oss-meta-a:a\nx-oss-meta-b:b\nx-oss-meta-c:c\n 以x-oss-为前缀的HTTP Header的字典序排列,可以为空。 - 如果设置CanonicalizedOSSHeaders为空,则无需在最后添加分隔符
\n
。 - 如果只有一个CanonicalizedOSSHeaders,则需要在最后添加分隔符
\n
,例如x-oss-meta-a\n
。 - 如果有多个CanonicalizedOSSHeaders,则需要在每一个CanonicalizedOSSHeaders之后添加分隔符
\n
,例如x-oss-meta-a:a\nx-oss-meta-b:b\nx-oss-meta-c:c\n
。
关于CanonicalizedOSSHeaders的构建方法,请参见构建CanonicalizedOSSHeaders的方法。
CanonicalizedResource 是 /examplebucket/ 用户想要访问的OSS资源,不能为空。 关于CanonicalizedResource的构建方法,请参见构建CanonicalizedResource的方法。
- 如果设置CanonicalizedOSSHeaders为空,则无需在最后添加分隔符
- 签名示例
请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: foo@bar.com x-oss-meta-magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-meta-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson 假设AccessKey ID为“44CF959******252F707”,AccessKey Secret为“OtxrzxIsfpFjA7Sw******8Bw21TLhquhboDYROV”,此处以Python为例介绍计算签名(Signature)的方法。
import hmac import hashlib h = hmac.new(oss2.to_bytes("OtxrzxIsfpFjA7Sw******8Bw21TLhquhboDYROV"), oss2.to_bytes("PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-meta-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson"), hashlib.sha1) signature = oss2.utils.b64encode_as_string(h.digest()) print("Signature: %s" % signature)
签名(Signature)计算结果应该为26NBxoKd******Dv6inkoDft/yA=,由于Authorization = “OSS”+ AccessKeyId + “:” + Signature,所以最后Authorization为“OSS 44CF95900***BF252F707:26NBxoKd******Dv6inkoDft/yA=”,然后加上Authorization头组成最后需要发送的消息。
PUT /nelson HTTP/1.0 Authorization:OSS 44CF95900***BF252F707:26NBxoKd******Dv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: foo@bar.com x-oss-meta-magic: abracadabra
细节分析如下:
- 如果传入的AccessKey ID不存在或未激活,则返回403 Forbidden错误,错误码为InvalidAccessKeyId;如果AccessKey ID已激活,但OSS判断用户的请求发生签名错误,则返回403 Forbidden错误,并在返回的response中显示正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。
返回示例如下:
<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B**** </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.*** </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VO**** </OSSAccessKeyId> </Error>
- 如果用户请求头中Authorization值的格式不对,则返回400 Bad Request错误,错误码为InvalidArgument。
- OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中日期的格式为:
date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)
说明 上述日期格式中“day”所占位数都是“2DIGIT”,因此“Jun 2”、“2 Jun 1982”和“2-Jun-1982”均是非法日期格式。- 如果签名验证时,头中没有传入Date或者Date格式不正确,则返回403 Forbidden错误,错误码为AccessDenied。
- 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden错误,错误码为RequestTimeTooSkewed。
构建CanonicalizedOSSHeaders的方法
所有以x-oss-为前缀的HTTP Header被称为CanonicalizedOSSHeaders,构建方法如下:
- 将所有以x-oss-为前缀的HTTP请求头的名称转换为小写的形式,例如
X-OSS-Meta-Name: TaoBao
转换为x-oss-meta-name: TaoBao
。 - 如果以从STS服务获取的临时访问凭证发送请求时,您还需要将获得的security-token值以
x-oss-security-token:security-token
的形式加入到签名字符串中。说明 关于搭建STS服务的具体操作,请参见开发指南中的 使用STS临时访问凭证访问OSS。您可以通过调用STS服务的 AssumeRole接口或者使用 各语言STS SDK来获取临时访问凭证。临时访问凭证包括临时访问密钥(AccessKeyId和AccessKeySecret)和安全令牌(SecurityToken)。 - 将步骤1中得到的所有HTTP请求头按照名称的字典序进行升序排列。
- 删除请求头和内容之间分隔符两端出现的任何空格。例如
x-oss-meta-name: TaoBao
转换为x-oss-meta-name:TaoBao
。 - 将每一个请求头和内容使用分隔符
\n
分隔拼成CanonicalizedOSSHeaders。
构建CanonicalizedResource的方法
用户发送请求中想访问的OSS目标资源被称为CanonicalizedResource,构建方法如下:
- 将CanonicalizedResource置为空字符串
""
。 - 设置要访问的OSS资源,格式为
/BucketName/ObjectName
。- 如果仅有BucketName而没有ObjectName,则CanonicalizedResource为”/BucketName/“。
- 如果既没有BucketName也没有ObjectName,则CanonicalizedResource为“/”。
- 如果请求的资源包括子资源(SubResource),则将所有的子资源按照字典序,从小到大排列并以
&
为分隔符生成子资源字符串。在CanonicalizedResource字符串尾添加?
和子资源字符串。此时的CanonicalizedResource为/BucketName/ObjectName?acl&uploadId=UploadId
。OSS目前支持的子资源(SubResource)包括acl、uploads、location、cors、logging、website、referer、lifecycle、delete、append、tagging、objectMeta、uploadId、partNumber、security-token、position、img、style、styleName、replication、replicationProgress、replicationLocation、cname、bucketInfo、comp、qos、live、status、vod、startTime、endTime、symlink、x-oss-process、response-content-type、response-content-language、response-expires、response-cache-control、response-content-disposition、response-content-encoding等。
子资源(SubResource)有以下三种类型:- 资源标识,例如子资源中的acl、append、uploadId、symlink等。更多信息,请参见关于Bucket的操作和关于Object的操作。
- 指定返回Header字段,例如
response-***
。更多信息,请参见GetObject的Request Parameters
。 - 文件(Object)处理方式,例如
x-oss-process
。更多信息,请参见图片处理。
计算签名头规则
- 签名的字符串必须为
UTF-8
格式。含有中文字符的签名字符串必须先进行UTF-8
编码,再与AccessKeySecret
计算最终签名。 - 签名的方法用RFC 2104中定义的HMAC-SHA1方法,其中Key指的是AccessKey Secret。
Content-Type
和Content-MD5
在请求中不是必须的,如果请求需要签名验证,空值请以换行符\n
代替。- 在所有非HTTP标准定义的Header中,只有以
x-oss-
开头的Header需要加入签名字符串(例如签名示例中的x-oss-meta-magic则需要加入签名字符串);其他非HTTP标准Header将被OSS忽略。说明 以x-oss-
开头的Header在签名验证前需要符合以下规范:- Header的名称需要变为小写。
- Header按字典序自小到大排序。
- 分割header name和value的冒号前后不能有空格。
- 每个Header之后都要有一个换行符“\n”,如果没有Header,则设置CanonicalizedOSSHeaders为空。
Content-MD5的计算方法
以消息内容“123456789”为例,以下详细说明正确及错误计算该字符串的Content-MD5的方法。
- 正确计算示例
- 先计算MD5加密的二进制数组(128位)。
- 对该二进制数组进行base64编码(而不是对32位字符串编码)。
以Python为例:>>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") //在Python 3中此处需要改为hash.update(b"0123456789")。 >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw=='
hash.digest(),计算出二进制数组(128位)。
>>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7'
- 错误计算示例
说明 常见错误是直接对计算出的32位字符串进行base64编码。
# hash.hexdigest(),计算得到可见的32位字符串编码。 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' # 错误的MD5值进行base64编码后的结果。 >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='