全部產品
Search
文件中心

Object Storage Service:在Header中包含V1簽名

更新時間:Jun 19, 2024

在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

OSSV1Signer.java

PHP

SignerV1.php

Node.js

client.js

Browser.js

Python

auth.py

.Net

OssRequestSigner.cs

Android

OSSUtils.java

Go

v1.go

iOS

OSSModel.m

C++

SignerV1.cc

C

oss_auth.c

Ruby

util.rb

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

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的方法

簽名樣本

  • 樣本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 22 Jun 1982以及2-Jun-1982均為非法日期格式。

    • 如果簽名驗證時,Authorization頭中沒有傳入Date,或者傳入的格式不正確,則返回403 Forbidden錯誤,錯誤碼為AccessDenied。

    • 傳入請求的時間必須在OSS伺服器目前時間之後的15分鐘以內,否則返回403 Forbidden錯誤,錯誤碼為RequestTimeTooSkewed。

構建CanonicalizedOSSHeaders的方法

所有以x-oss-為首碼的HTTP Header被稱為CanonicalizedOSSHeaders,構建方法如下:

  1. 將所有以x-oss-為首碼的HTTP要求標頭的名稱轉換為小寫形式,例如X-OSS-Meta-Name: TaoBao轉換為x-oss-meta-name: TaoBao

  2. 如果以從STS服務擷取的臨時訪問憑證發送請求時,您還需要將獲得的security-token值以x-oss-security-token:security-token的形式加入到簽名字串中。

    說明

    關於搭建STS服務的具體操作,請參見使用STS臨時訪問憑證訪問OSS。您可以通過調用STS服務的AssumeRole介面或者使用各語言STS SDK來擷取臨時訪問憑證。臨時訪問憑證包括臨時存取金鑰(AccessKey ID和AccessKey Secret)和安全性權杖(SecurityToken)。

  3. 將擷取的所有HTTP要求標頭按照名稱的字典序進行升序排列。

  4. 刪除要求標頭和內容之間分隔字元兩端出現的任何空格。例如x-oss-meta-name: TaoBao轉換為x-oss-meta-name:TaoBao

  5. 將每一個要求標頭和內容使用分隔字元\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-TypeContent-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的方法。

  • 正確計算樣本

    1. 先計算MD5加密的位元組(128位)。

    2. 對該位元組進行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='