全部產品
Search
文件中心

Microservices Engine:hmac-auth外掛程式

更新時間:Oct 12, 2024

hmac-auth外掛程式實現了基於HMAC演算法為HTTP請求產生不可偽造的簽名,並基於簽名實現身份認證和鑒權。本文介紹如何配置hmac-auth外掛程式。

外掛程式類型

認證鑒權。

配置欄位

認證配置

名稱

資料類型

填寫要求

預設值

描述

consumers

array of object

必填。

-

佈建服務的調用者,用於對請求進行認證。

date_offset

number

選填。

-

配置允許的用戶端最大時間位移,單位為秒。根據要求標頭Date解析用戶端UTC時間,可用於避免請求重放。未配置時,不做校正。

global_auth

array of string

選填(**僅執行個體層級配置**)

-

只能在執行個體層級配置,若配置為true,則全域生效認證機制; 若配置為false,則只對做了配置的網域名稱和路由生效認證機制,若不配置則僅當沒有網域名稱和路由配置時全域生效(相容老使用者使用習慣)。

子項consumers中每一項的配置欄位說明如下。

名稱

資料類型

填寫要求

預設值

描述

key

string

必填。

-

配置該consumer的訪問憑證。

secret

string

必填。

-

配置用於產生簽名的secret。

name

string

必填。

-

配置該consumer的名稱。

鑒權配置(非必需)

名稱

資料類型

填寫要求

預設值

描述

allow

array of string

選填(**非執行個體層級配置**)。

-

只能在路由或網域名稱等細粒度規則上配置,對於符合匹配條件的請求,配置允許訪問的 consumer,從而實現細粒度的許可權控制。

重要
  • 在一個規則裡,鑒權配置和認證配置不可同時存在。

  • 對於通過認證鑒權的請求,請求的Header會被添加一個X-Mse-Consumer欄位,用以標識調用者的名稱。

配置樣本

全域配置認證和路由粒度進行鑒權

以下配置將對網關特定路由或網域名稱開啟 Hmac Auth 認證和鑒權。注意key欄位不能重複。

在執行個體層級做如下外掛程式配置:

global_auth: false
consumers: 
- key: appKey-example-1
  secret: appSecret-example-1
  name: consumer-1
- key: appKey-example-2
  secret: appSecret-example-2
  name: consumer-2

route-aroute-b兩個路由做如下外掛程式配置:

allow:
- consumer1

*.example.comtest.com兩個網域名稱做如下外掛程式配置:

allow:
- consumer2
說明
  • 此例指定的route-aroute-b即在建立網關路由時填寫的路由名稱,當匹配到這兩個路由時,將允許nameconsumer1的調用者訪問,其他調用者不允許訪問。

  • 此例指定的*.example.comtest.com用於匹配請求的網域名稱,當發現網域名稱匹配時,將允許nameconsumer2的調用者訪問,其他調用者不被允許訪問。

網關執行個體層級開啟

global_auth: true
consumers: 
- key: appKey-example-1
  secret: appSecret-example-1
  name: consumer-1
- key: appKey-example-2
  secret: appSecret-example-2
  name: consumer-2

簽名機制說明

配置準備

如上指引,在外掛程式配置中配置產生和驗證簽名所需的憑證配置。

  • key: 用於要求標頭x-ca-key中設定。

  • secret: 用於產生請求籤名。

用戶端簽名產生方式

流程簡介

用戶端產生簽名共分三步處理。

  1. 從原始請求中提取關鍵資料,得到一個用來簽名的字串。

  2. 使用密碼編譯演算法和配置的secret對關鍵資料簽名串進行加密處理,得到簽名。

  3. 將簽名所相關的所有頭加入到原始HTTP請求中,得到最終HTTP請求。

簽名串提取流程

用戶端需要從HTTP請求中提取出關鍵資料,組合成一個簽名串,產生的簽名串的格式如下。

HTTPMethod
Accept
Content-MD5
Content-Type
Date
Headers
PathAndParameters

以上7個欄位構成整個簽名串,欄位之間使用\n間隔,如果Headers為空白,則不需要加\n,其他欄位如果為空白都需要保留\n。簽名大小寫敏感。

每個欄位的擷取規則如下。

  • HTTPMethod:HTTP的方法,全部大寫,比如POST。

  • Accept:請求中的Accept頭的值,可為空白。建議顯式設定 Accept Header。當 Accept 為空白時,部分HTTP用戶端會給Accept設定預設值為*/*,導致簽名校正失敗。

  • Content-MD5:請求中的Content-MD5頭的值,可為空白。當請求存在Body且Body為非Form形式時才計算Content-MD5頭(請確保在要求標頭中添加Content-MD5 ),下面是Java的Content-MD5值的參考計算方式。

    String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));
  • Content-Type:請求中的Content-Type頭的值,可為空白。

  • Date:請求中的Date頭的值,當未開啟date_offset配置時,可為空白,否則將用於時間位移校正。

  • Headers:您可以選取指定的Header參與簽名,關於Header的簽名串拼接方式有以下規則。

    • 參與簽名計算的Header的Key按照字典排序後使用如下方式拼接。

      HeaderKey1 + ":" + HeaderValue1 + "\n"\+
      HeaderKey2 + ":" + HeaderValue2 + "\n"\+
      ...
      HeaderKeyN + ":" + HeaderValueN + "\n"
    • 某個Header的Value為空白,則使用HeaderKey+":"+"\n"參與簽名,需要保留Key和英文冒號。

    • 所有參與簽名的Header的Key的集合使用英文逗號分割放到Key為X-Ca-Signature-Headers的Header中。

    • 以下Header不參與Header簽名計算:X-Ca-Signature、X-Ca-Signature-Headers、Accept、Content-MD5、Content-Type、Date。

  • PathAndParameters: 這個欄位包含Path、Query和Form中的所有參數,具體組織形式如下。

    Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2 + ... "&" + KeyN + "=" + ValueN
說明
  • Query和Form參數對的Key按照字典排序後使用上面的方式拼接。

  • Query和Form參數為空白時,則直接使用Path,不需要添加。

  • Query和Form存在數組參數時(Key相同,Value不同的參數) ,取第一個Value參與簽名計算。

簽名串提取樣本

初始的HTTP請求。

POST /http2test/test?param1=test HTTP/1.1
host:api.aliyun.com
accept:application/json; charset=utf-8
ca_version:1
content-type:application/x-www-form-urlencoded; charset=utf-8
x-ca-timestamp:1525872629832
date:Wed, 09 May 2018 13:30:29 GMT+00:00
user-agent:ALIYUN-ANDROID-DEMO
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
content-length:33
username=xiaoming&password=123456789

產生的正確簽名串。

POST
application/json; charset=utf-8
application/x-www-form-urlencoded; charset=utf-8
Wed, 09 May 2018 13:30:29 GMT+00:00
x-ca-key:203753385
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
x-ca-signature-method:HmacSHA256
x-ca-timestamp:1525872629832
/http2test/test?param1=test&password=123456789&username=xiaoming

簽名計算流程

用戶端從HTTP請求中提取出關鍵資料群組裝成簽名串後,需要對簽名串進行加密及編碼處理,形成最終的簽名。

具體的加密形式如下,其中stringToSign是提取出來的簽名串,secret是外掛程式配置中填寫的,sign是最終產生的簽名。

Mac hmacSha256 = Mac.getInstance("HmacSHA256");
byte[] secretBytes = secret.getBytes("UTF-8");
hmacSha256.init(new SecretKeySpec(secretBytes, 0, secretBytes.length, "HmacSHA256"));
byte[] result = hmacSha256.doFinal(stringToSign.getBytes("UTF-8"));
String sign = Base64.encodeBase64String(result);

stringToSign使用UTF-8解碼後得到Byte數組,然後使用密碼編譯演算法對Byte數組進行加密,然後使用Base64演算法進行編碼,形成最終的簽名。

添加簽名流程

用戶端需要將以下四個Header放在HTTP請求中傳輸給API Gateway,進行簽名校正。

  • x-ca-key:取值APP Key。必選。

  • x-ca-signature-method:簽名演算法。取值HmacSHA256或者HmacSHA1,可選,預設值為HmacSHA256。

  • x-ca-signature-headers:所有簽名頭的Key的集合。使用英文逗號分隔,可選。

  • x-ca-signature:簽名。必選。

下面是攜帶簽名的整個HTTP請求的樣本。

POST /http2test/test?param1=test HTTP/1.1
host:api.aliyun.com
accept:application/json; charset=utf-8
ca_version:1
content-type:application/x-www-form-urlencoded; charset=utf-8
x-ca-timestamp:1525872629832
date:Wed, 09 May 2018 13:30:29 GMT+00:00
user-agent:ALIYUN-ANDROID-DEMO
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
x-ca-key:203753385
x-ca-signature-method:HmacSHA256
x-ca-signature-headers:x-ca-timestamp,x-ca-key,x-ca-nonce,x-ca-signature-method
x-ca-signature:xfX+bZxY2yl7EB/qdoDy9v/uscw3Nnj1pgoU+Bm6xdM=
content-length:33
username=xiaoming&password=123456789

服務端簽名驗證方式

流程簡介

伺服器驗證用戶端簽名一共分四步處理。

  1. 從接收到的請求中提取關鍵資料,得到一個用來簽名的字串。

  2. 從接收到的請求中讀取key,通過key查詢到對應的secret

  3. 使用密碼編譯演算法和secret對關鍵資料簽名串進行加密處理,得到簽名。

  4. 從接收到的請求中讀取用戶端簽名,對比伺服器端簽名和用戶端簽名的一致性。

簽名排錯方法

網關簽名校正失敗時,會將服務端的簽名串(StringToSign)放到HTTP Response的Header中返回到用戶端,Key為:X-Ca-Error-Message,您只需要將本地計算的簽名串(StringToSign)與服務端返回的簽名串進行對比即可找到問題。

如果服務端與用戶端的StringToSign一致請檢查用於簽名計算的APP Secret是否正確。

因為HTTP Header中無法表示換行,因此StringToSign中的分行符號都被替換成#,如下所示。

X-Ca-Error-Message:  Server StringToSign:`GET#application/json##application/json##X-Ca-Key:200000#X-Ca-Timestamp:1589458000000#/app/v1/config/keys?keys=TEST`

相關錯誤碼

HTTP狀態代碼

出錯資訊

原因說明

400

Invalid Signature.

要求標頭x-ca-signature簽名串,與服務端計算得到簽名不一致。

400

Invalid Content-MD5.

要求標頭content-md5不正確。

400

Invalid Date.

根據要求標頭date計算時間位移超過配置的date_offset。

401

Invalid Key.

要求標頭未提供x-ca-key,或者x-ca-key無效。

401

Empty Signature.

要求標頭未提供x-ca-signature簽名串。

403

Unauthorized Consumer.

請求的調用方無存取權限。

413

Request Body Too Large.

請求Body超過限制大小:32MB。

413

Payload Too Large.

請求Body超過全域配置DownstreamConnectionBufferLimits,請在參數配置頁調高此項。

說明

注意謹慎調高DownstreamConnectionBufferLimits此參數配置,調高後網關記憶體使用量將有顯著增加。