在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='