基於HMAC-SHA1的RESTful API 授權簽名方法

fxm547發表於2018-01-22

首發於fxm5547的部落格

引言

為了避免API被非法呼叫,呼叫過程中被篡改和重放攻擊,需要增加API呼叫授權。對呼叫資訊進行簽名和驗籤是常用的授權方法。呼叫雙方約定祕鑰並內部存放,利用祕鑰基於hash演算法(常用的有MD5,SHA1和SHA256)通過HMAC運算生產簽名signature。

參考

傳遞方式

  • 通過header傳遞,格式:Authorization: CoAPI-HMAC-SHA1 $sign
  • 同時傳遞header X-Co-TimeStamp,格式:X-Co-TimeStamp: 1493030704

簽名過程

$sign = base64(hmac-sha1(SecretKey,
            HTTPRequestMethod + "\n"
            + CanonicalURI + "\n"
            + CanonicalQueryString + "\n"
            + CanonicalHeaders + "\n"
            + CanonicalBody))
複製程式碼
  • SecretKey 表示簽名所需的金鑰,服務端儲存不傳遞;
  • HTTPRequestMethod 表示HTTP 請求的Method,主要有GET,POST,PUT,DELETE, HEAD,OPTION等,使用大寫;
  • \n表示換行符;
  • CanonicalURI 表示格式化後的請求URI=Host + pathpath使用/開頭(即使後面為空)。例子:api.url.com/shop/v1/goods/9642
  • CanonicalQueryString 表示格式化後的請求引數字串,可為空。對請求引數按照key的字典序排列(PHP的ksort())後,進行以下拼接
CanonicalQueryString = (key1=urlEncode(val1)&key2=urlEncode(val2)...)
複製程式碼

urlEncode指遵循RFC 3986的URL Encode(PHP中的rawurlencode())。

  • CanonicalHeaders 表示格式化後的Headers,只使用X-Co-AppX-Co-TimeStamp
CanonicalHeaders = lower("X-Co-App") + ':' + trim(HeaderValue) + "\n"
                   + lower("X-Co-TimeStamp") + ':' + trim(HeaderValue)
複製程式碼

lower()表示轉換為小寫,trim()表示去除前後空格。

  • CanonicalBody 表示格式後的Body,可為空。API的Body都是Json,對Json的第一層元素按照key的字典序排列(PHP的ksort())後,進行以下拼接
CanonicalBody = (key1=val1&kay2=val2...)
複製程式碼

如果value是物件或陣列,對其進行json encode。

簽名驗證失敗

  • 如果Header中的X-Co-TimeStamp和伺服器的時間差15分鐘以上,拒絕該服務,並返回InvalidSign 簽名已過期錯誤;
  • 簽名錯誤,拒絕該服務,並返回InvalidSign 簽名校驗錯誤錯誤。

相關文章