在OSS中,使用HTTP請求的Authorization Header來攜帶簽名信息是進行身份驗證的最常見方法。除了使用POST簽名和URL簽名之外,所有的OSS操作都需要通過Authorization Header來進行身份驗證。本文介紹如何使用V1簽名算法來在Header中包含簽名。
OSS支持更安全的V4簽名算法,建議您使用V4簽名。更多信息,請參見V4簽名。
SDK簽名實現
OSS SDK已自動實現V1簽名,您使用OSS SDK時無需關注簽名問題。如果您想了解具體語言的簽名實現,請參考OSS SDK的代碼。OSS SDK簽名實現的文件請參見下表。
SDK | 簽名實現 |
Java | |
PHP | |
Node.js | |
Browser.js | |
Python | |
.Net | |
Android | |
Go | |
iOS | |
C++ | |
C | |
Ruby |
Authorization字段計算的方法
計算方法
Authorization = "OSS " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ Content-MD5 + "\n"
+ Content-Type + "\n"
+ Date + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource))
參數說明
參數 | 類型 | 是否必選 | 示例值 | 說明 |
AccessKeyId | 字符串 | 是 | LTAI******************** | 填寫當前賬號的訪問密鑰AccessKey,包括AccessKey ID和AccessKey Secret。
|
AccessKeySecret | 字符串 | 是 | Q0Ye************************** | |
x-oss-security-token | 字符串 | 否 | CAIS******************************** | STS安全令牌。僅當使用STS構造Header簽名時,才需要設置此參數。關于如何獲取Security-Token的具體操作,請參見AssumeRole - 獲取扮演角色的臨時身份憑證。 |
VERB | 枚舉值 | 是 | PUT | HTTP請求的Method,包含PUT、GET、POST、HEAD、DELETE、OPTIONS等。 |
\n | 字符串 | 否 | \n | 換行符。 |
Content-MD5 | 字符串 | 否 | eB5eJF1ptWaXm4bijSPyxw== | 請求內容數據的MD5值,對消息內容(不包括頭部)計算MD5值獲得128比特位數字,對該數字進行base64編碼得出。更多信息,請參見RFC2616 Content-MD5。 該請求頭可用于消息合法性的檢查(消息內容是否與發送時一致),也可以為空。 關于Content-MD5的計算方法,請參見Content-MD5的計算方法。 |
Content-Type | 字符串 | 否 | application/octet-stream | 請求內容的類型,也可以為空。 說明 如果生成簽名時沒有設置Content-Type,則后續使用簽名上傳文件時也無需設置該參數。 |
Date | 字符串 | 是 | Sun, 22 Nov 2015 08:16:38 GMT | 此次操作的時間,Date必須為GMT格式,且不能為空。該值取自請求頭的Date字段或者x-oss-date字段。當這兩個字段同時存在時,以x-oss-date為準。 重要 如果請求中的Date時間和OSS服務器的當前時間差15分鐘以上,OSS服務器將拒絕該請求,并返回HTTP 403錯誤。 |
CanonicalizedOSSHeaders | 字符串 | 否 | x-oss-meta-a:a\nx-oss-meta-b:b\nx-oss-meta-c:c\n | 以
關于CanonicalizedOSSHeaders的構建方法,請參見構建CanonicalizedOSSHeaders的方法。 |
CanonicalizedResource | 字符串 | 是 | examplebucket | 您希望訪問的OSS資源,不能為空。 關于CanonicalizedResource的構建方法,請參見構建CanonicalizedResource的方法。 |
簽名示例
示例1(包含所有參數)
請求
簽名字符串計算公式
簽名字符串
PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Wed, 28 Dec 2022 10:27:41 GMT Host: examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice 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 Wed, 28 Dec 2022 10:27:41 GMT\n x-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/examplebucket/nelson
假設AccessKey ID為LTAI********************,AccessKey Secret為Q0Ye**************************,此處以Python為例介紹計算簽名(Signature)的方法。
import hmac import hashlib import base64 h = hmac.new("Q0Ye**************************".encode('utf-8'), "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM\ntext/html\nWed, 28 Dec 2022 10:27:41 GMT\nx-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/oss-example/nelson".encode('utf-8'), hashlib.sha1) signature = base64.encodebytes(h.digest()) print(signature)
簽名(Signature)計算結果為
J9Nl************************
,結合Authorization頭的結構組成,需要發送的消息體如下。PUT /nelson HTTP/1.0 Authorization:OSS LTAI********************:J9Nl************************ Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Wed, 28 Dec 2022 10:27:41 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
示例2(不包含可選參數Content-MD5以及Content-Type)
請求
簽名字符串計算公式
簽名字符串
PUT /nelson HTTP/1.0 Date: Wed, 28 Dec 2022 09:56:32 GMT Host: examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + “\n”+ “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource))
PUT\n\n\nWed, 28 Dec 2022 09:56:32 GMT\n x-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/examplebucket/nelson
假設AccessKey ID為LTAI********************,AccessKey Secret為KZo1**************************,此處以Python為例介紹計算簽名(Signature)的方法。
import hmac import hashlib import base64 h = hmac.new("KZo1**************************".encode('utf-8'), "PUT\n\n\nWed, 28 Dec 2022 09:56:32 GMT\nx-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/oss-example/nelson".encode('utf-8'), hashlib.sha1) signature = base64.encodebytes(h.digest()) print(signature)
簽名(Signature)計算結果為
Mhb1************************
,結合Authorization頭的結構組成,需要發送的消息體如下。PUT /nelson HTTP/1.0 Authorization:OSS LTAI********************:Mhb1************************ Date: Wed, 28 Dec 2022 09:56:32 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice 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 /examplebucket?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
均為非法日期格式。如果簽名驗證時,Authorization頭中沒有傳入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來獲取臨時訪問憑證。臨時訪問憑證包括臨時訪問密鑰(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)。
將獲取的所有HTTP請求頭按照名稱的字典序進行升序排列。
刪除請求頭和內容之間分隔符兩端出現的任何空格。例如
x-oss-meta-name: TaoBao
轉換為x-oss-meta-name:TaoBao
。將每一個請求頭和內容使用分隔符
\n
分隔拼成CanonicalizedOSSHeaders。
構建CanonicalizedResource的方法
發送請求中希望訪問的OSS目標資源被稱為CanonicalizedResource,構建方法如下:
如果既有BucketName也有ObjectName,則CanonicalizedResource格式為/BucketName/ObjectName
如果僅有BucketName而沒有ObjectName,則CanonicalizedResource格式為/BucketName/。
如果既沒有BucketName也沒有ObjectName,則CanonicalizedResource為正斜線(/)。
如果請求的資源包括子資源(SubResource),則所有的子資源需按照字典序升序排列,并以
&
為分隔符生成子資源字符串。在CanonicalizedResource字符串尾添加?
和子資源字符串。此時的CanonicalizedResource為/BucketName/ObjectName?acl&uploadId=UploadId
。OSS支持以下四種類型的子資源:
資源標識,例如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、callback、callback-var等。更多信息,請參見關于Bucket的操作和關于Object的操作。
重要資源標識嚴格區分大小寫。
指定返回Header字段,例如response-content-type、response-content-language、response-expires、response-cache-control、response-content-disposition、response-content-encoding等。更多信息,請參見GetObject。
圖片處理操作方式,例如
x-oss-process
。更多信息,請參見圖片處理。以
x-oss-ac-*
開頭的訪問控制字段,例如x-oss-ac-source-ip、x-oss-ac-subnet-mask、x-oss-ac-vpc-id、x-oss-ac-forward-allow。更多信息,請參見簽名版本1。說明使用包含x-oss-ac-source-ip參數的CanonicalizedResource生成簽名后,請從需要發送的消息query參數中移除x-oss-ac-source-ip,以保護IP地址信息安全。
計算簽名頭規則
簽名的字符串必須為
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的計算方法
以消息內容“0123456789”為例,以下詳細說明正確及錯誤計算該字符串的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='