一文帶你掌握OBS的兩種常見的鑑權方式

摘要:本文就將帶您瞭解OBS的兩種常見的鑑權方式——Header攜帶簽名和URL攜帶簽名。

OBS提供了REST(Representational State Transfer)風格API,支持您經過HTTP/HTTPS請求調用。在調用OBS的API前,須要瞭解OBS的鑑權認證方式。本文就將帶您瞭解OBS的兩種常見的鑑權方式——Header攜帶簽名和URL攜帶簽名。html

一、在Header中攜帶簽名計算

官網連接:https://support.huaweicloud.com/api-obs/obs_04_0010.html算法

1.一、簽名的計算原理和計算方法

原理圖示segmentfault

計算方法api

(1).構造請求字符串(StringToSign)。數組

請求字符串的構造方法以下:瀏覽器

`StringToSign =

HTTP-Verb + "\\n" +

Content-MD5 + "\\n" +

Content-Type + "\\n" +

Date + "\\n" +

CanonicalizedHeaders + CanonicalizedResource`

(2).對第一步的結果進行UTF-8編碼。工具

(3).使用SK對第二步的結果進行HMAC-SHA1簽名計算。編碼

(4).對第三步的結果進行Base64編碼,獲得簽名。加密

簽名如如下形式(28位長度的BASE64編碼的字符串):url

JONydLd9zpf+Eu3IYiUjNmukHN0=

計算示例

例:須要獲取桶」obs-test」下的對象log.conf的對象ACL,如何構造請求並計算簽名?

一、首先明確StringToSign的各字段:

請求方法:GET;

請求MD5:空

Content-Type:空

請求時間:Tue, 28 Jul 2020 06:29:47 GMT(即北京時間2020年7月28日14:29:47)

自定義頭域(CanonicalizedHeaders):空

規範化資源(CanonicalizedResource):/obs-test/log.conf?acl

二、構造請求字符串StringToSign以下:

StringToSign = ‘’’GET
 
 
Tue, 28 Jul 2020 06:29:47 GMT
/obs-test/log.conf?acl’’’

三、根據簽名算法,將StringToSign進行HMAC-SHA1計算後進行BASE64編碼得到簽名結果:xYlcrwT9jSaCtY0OnBE01OBR+aA=

1.二、簽名計算的實現方式

以Python計算簽名代碼爲例,供參考:

import hashlib  
 import hmac  
 import binascii  
 from datetime import datetime  
    
  # 驗證信息  
  AK = '您的access_key_id'  
 SK = '您的secret_access_key_id'  
  
# 指定HTTP方法,可選GET/PUT/DELETE/POST/OPTIONS  
httpMethod = "GET"  
 
# 指定請求的Header:Content-Type和Content-MD5  
contentType = ""  
 conten**5 = ""  
  
 # 使用datetime庫生成時間,若是須要自定義請求時間請保持格式一致  
 date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')  
   
 # 填寫canonicalizedHeaders  
# canonicalizedHeaders = "x-obs-acl:public-read"  
 # canonicalizedHeaders = "x-obs-acl:public-read\n"+'x-obs-storage-class:WARM\n'  
 canonicalizedHeaders = ""  
   
 # 填寫CanonicalizedResource  
 # CanonicalizedResource = "/BucketName/ObjectName"  
 # CanonicalizedResource = "/BucketName/ObjectName?acl"  
 # CanonicalizedResource = "/"
 CanonicalizedResource = "/BucketName/"  
  
# 生成StringToSign  
 canonical_string = httpMethod + "\n" + conten**5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedHeaders + CanonicalizedResource  
 
 # 計算簽名並進行BASE64編碼  
 hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1)  
 encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8')  
  
 # 打印StringToSign以便出現問題時進行驗證  
 print(canonical_string)  
   
 # 打印簽名  
 print(encode_canonical)

C語言簽名算法示例:

請參考https://obs-community.obs.cn-north-1.myhuaweicloud.com/sign/signature_c.zip,下載C語言簽名計算代碼樣例,其中:

計算簽名的接口包含在sign.h頭文件中。

計算簽名的示例代碼在main.c文件中。

可視化簽名計算工具:

您也能夠經過OBS提供的可視化簽名計算工具來計算簽名。

工具連接:

https://obs-community.obs.cn-north-1.myhuaweicloud.com/sign/header_signature.html

說明:

1. canonicalizedHeaders:表示HTTP請求頭域中的OBS請求頭字段,即以「x-obs-」做爲前輟的頭域,如「x-obs-date,x-obs-acl,x-obs-meta-*」;

a.請求頭字段中關鍵字的的全部字符要轉爲小寫,須要添加多個字段時,要將全部字段按照關鍵字的字典序從小到大進行排序;

b.在添加請求頭字段時,若是有重名的字段,則須要進行合併。如:x-obs-meta-name:name1和x-obs-meta-name:name2,則須要先將重名字段的值(這裏是name1和name2)以逗號分隔,合併成x-obs-meta-name:name1,name2;

c.頭域中的請求頭字段中的關鍵字不容許含有非ASCII碼或不可識別字符;請求頭字段中的值也不建議使用非ASCII碼或不可識別字符,若是必定要使用非ASCII碼或不可識別字符,須要客戶端自行作編解碼處理,能夠採用URL編碼或者Base64編碼,服務端不會作解碼處理;

d.當請求頭字段中含有無心義空格或table鍵時,須要摒棄。例如:x-obs-meta-name: name(name前帶有一個無心義空格),須要轉換爲:x-obs-meta-name:name;

e.每個請求頭字段最後都須要另起新行。

2. canonicalizedResource表示HTTP請求所指定的OBS資源,構造方式以下:

<桶名+對象名>+[子資源] …

a.經過桶綁定的自定義域名訪問OBS,桶名由自定義域名錶示,則爲"/obs.ccc.com/object",其中「obs.ccc.com」爲桶綁定的自定義域名。若是沒有對象名,如列舉桶,則爲"/obs.ccc.com/";

b.不是經過桶綁定的自定義域名訪問OBS的場景,則爲"/bucket/object",若是沒有對象名,如列舉桶,則爲"/bucket/"。若是桶名也沒有,則爲「/」;

c.若是有子資源,則將子資源添加進來,例如?acl,?logging。

3. 如須要使用臨時AK/SK+SecurityToken的方式計算簽名,計算簽名的方法保持一致,但須要在頭域中添加「x-obs-security-token:…」字段。

4.計算Content-MD5的方法見文末的說明。

5.其餘語言計算簽名的代碼可詳見對應語言的SDK,詳見:

https://support.huaweicloud.com/sdkreference-obs/obs_02_0001.html

1.三、常見問題

1.訪問OBS時報錯:Signature Does Not Match

簽名不匹配的狀況主要有如下兩種可能:

a.您沒有使用正確的AK/SK,您能夠檢查您計算簽名使用的SK和發送請求時所攜帶的AK是否正確且匹配;

b.您計算簽名時構造的StringToSign和服務端根據接收到的HTTP請求所計算的StringToSign不匹配,您能夠檢查服務端返回的StringToSign,並與本地計算簽名所使用的StringToSign進行對比。

以下圖是服務端返回的由接收到HTTP請求所還原的StringToSign,您能夠經過對比您本地的StringToSign和您發送到服務端的HTTP請求,來分析您簽名計算失敗的緣由。

2.訪問OBS時報錯:Request has expired

此類狀況請您檢查您攜帶的Date是否正確,爲保證請求的時效性,您所攜帶的Date頭域必須與服務端的時間相差在15分鐘之內(服務端爲UTC時間),如您攜帶了x-obs-date頭域,需檢查x-obs-date的時間是否與服務端時間相差15分鐘之內。

二、在URL中攜帶簽名

OBS服務支持用戶構造一個特定操做的URL,這個URL中會包含用戶AK、簽名、有效期、資源等信息,任何拿到這個URL的人都可執行這個操做,OBS服務收到這個請求後認爲該請求就是簽發URL用戶本身在執行操做。例如構造一個攜帶簽名信息的下載對象的URL,拿到相應URL的人能下載這個對象,但該URL只在Expires指定的失效時間內有效。URL中攜帶簽名主要用於在不提供給其餘人Secret Access Key的狀況下,讓其餘人能用預簽發的URL來進行身份認證,並執行預約義的操做。

官網連接https://support.huaweicloud.com/api-obs/obs_04_0011.html

2.一、簽名的計算原理和計算方法

原理圖示

計算方法

1.構造請求字符串(StringToSign)。

請求字符串的構造方法以下:

StringToSign =

HTTP-Verb + "\\n" +

Content-MD5 + "\\n" +

Content-Type + "\\n" +

Date + "\\n" +

CanonicalizedHeaders + CanonicalizedResource

2.對第一步的結果進行UTF-8編碼。

3.使用SK對第二步的結果進行HMAC-SHA1簽名計算。

4.對第三步的結果進行Base64編碼,獲得簽名。

簽名如如下形式(28位長度的BASE64編碼的字符串):

JONydLd9zpf+Eu3IYiUjNmukHN0=

URL中攜帶的簽名計算方法同Header中攜帶簽名的簽名計算方法,可是須要將Date更換爲UNIX時間戳。

攜帶簽名的URL形式以下:

obs-ycytest.obs.cn-north-1.myhuaweicloud.com/?AccessKeyId=YN97UCJEKF2ALJ44AHAN&Expires=1575452568&Signature=0wG/GF7XgmOatCFhwHJh0J6NrtQ=

其對應的StringToSign爲

GET

1575452568
/obs-ycytest/

URL中攜帶的參數具體含義見下表:

計算示例

例:須要獲取桶」obs-test」下的對象log.conf的對象ACL,如何構造請求並計算簽名?

一、首先明確StringToSign的各字段:

請求方法:GET;
請求MD5:空
Content-Type:空
請求時間:1595918661(即北京時間2020年7月28日14:44:21)
自定義頭域(CanonicalizedHeaders):空
規範化資源(CanonicalizedResource):/obs-test/log.conf?acl

二、構造請求字符串StringToSign以下:

StringToSign = ‘’’GET
 
 
1595918661
/obs-test/log.conf?acl’’’

三、根據簽名算法,將StringToSign進行HMAC-SHA1計算後進行BASE64編碼得到簽名結果:lLcYw1fFMJv5m+MS0XenNrqJlag=

根據計算的結果,將URL拼接起來便可生成攜帶簽名的URL以下:

obs-test.obs.myhuaweicloud.com/log.conf?AccessKeyId=xxx&acl&Expires=1595918661&Signature= lLcYw1fFMJv5m+MS0XenNrqJlag=

2.二、簽名計算的實現方式

在URL中攜帶簽名時,只需將Date替換爲UNIX時間戳便可計算對應的簽名,所以對應的代碼再也不贅述。

如須要使用臨時AK/SK+SecurityToken的方式計算簽名,計算簽名的方法保持一致,但須要在對應的CanonicalizedResource中添加「?x-obs-security-token=…」字段,且計算獲得的簽名必需要進行URL編碼。使用臨時AK/SK+SecurityToken計算簽名的代碼以下:

import hashlib  
  import hmac  
  import binascii  
  import urllib.request  
    
  AK = 'Input Your AccessKeyId'  
 SK = 'Input Your SecretKeyId'  
 Token = 'Input Your SecurityToken'  
    
 httpMethod = "GET"  
 contentType = ""  
 Conten**5 = ''  
 date = '1594972984'  
 canonicalizedHeaders = ''  
 CanonicalizedResource = "/messageflow/flowengine.tar.gz" + "?x-obs-security-token=" + Token  
 canonical_string = httpMethod + "\n" + Conten**5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedHeaders + CanonicalizedResource  
 hashed = hmac.new(SK.encode('UTF-8'), canonical_string.encode('UTF-8'), hashlib.sha1)  
 encode_canonical = binascii.b2a_base64(hashed.digest())[:-1].decode('UTF-8')  
   
 url= 'messageflow.obs.myhuaweicloud.com/flowengine.tar.gz?x-obs-security-token={}&Expires={}&AccessKeyId={}&Signature={}'.format(Token, date, AK, urllib.request.quote(encode_canonical))  
 print(url)

說明:

1.在計算簽名時,Date表示的是一個UNIX時間戳;

2.若是想要在瀏覽器中使用URL中攜帶簽名生成的預約於URL,則計算簽名時不要使用「Content-MD5」、「Content-Type」、「CanonicalizedHeaders」計算簽名,不然瀏覽器不能攜帶這些參數,請求發送到服務端以後,會提示簽名錯誤。

三、Content-MD5的計算方式

3.一、Content-MD5的計算方法

以消息內容「0123456789」爲例,如下詳細說明計算該字符串的Content-MD5的方法。

1.先計算MD5加密的二進制數組(128位)。

2.對這個二進制數組進行base64編碼(而不是對32位字符串編碼)。

以Python爲例:

>>> import base64,hashlib
>>> hash = hashlib.md5()
>>> hash.update("0123456789".encode(‘utf-8’))
>>> base64.b64encode(hash.digest())
'eB5eJF1ptWaXm4bijSPyxw=='
注:hash.digest(),計算出二進制數組(128位)。
>>> hash.digest()
'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7'

3.二、Content-MD5計算的實現

以Python計算文件MD5代碼爲例,供參考:

import os  
 import base64  
 import hashlib  
   
  
  def md5_file_encode_by_size_offset(file_path=None, size=None, offset=None, chuckSize=None):  
     if file_path is not None and size is not None and offset is not None:  
         m = hashlib.md5()  
        with open(file_path, 'rb') as fp:  
             CHUNKSIZE = 65536 if chuckSize is None else chuckSize  
             fp.seek(offset)  
            read_count = 0  
             while read_count < size:  
                read_size = CHUNKSIZE if size - read_count >= CHUNKSIZE else size - read_count  
                data = fp.read(read_size)  
                 read_count_once = len(data)  
                if read_count_once <= 0:  
                    break 
                 m.update(data)  
                 read_count += read_count_once  
         return base64.b64encode(m.digest()).decode()  
   
   
 file_path = r'Input Your File Path'  
 size = os.path.getsize(file_path)  
 Conten**5 = md5_file_encode_by_size_offset(file_path=file_path, size=size, offset=0)  
 print(Conten**5)

3.三、常見問題

常見錯誤是直接對計算出的32位字符串進行base64編碼。

# hash.hexdigest(),計算獲得可見的32位字符串編碼。
>>> import base64,hashlib
>>> hash = hashlib.md5()
>>> hash.update("0123456789".encode(‘utf-8’))
>>> hash.hexdigest()
'781e5e245d69b566979b86e28d23f2c7'

# 錯誤的MD5值進行base64編碼後的結果:

>>> base64.b64encode(hash.hexdigest())
'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索