API簽名驗證的三種套路——以及我們怎麼被第三種坑了半天
你調一個第三方API,簽名死活不對——然後你發現文件根本沒寫清楚 這是一個真實故事。今天下午,我們在對接一個DNS管理平台的API,需要通過API自動建立DNS記錄。API文件寫著:「使用MD5簽名驗證」。 聽起來很簡單對吧?把參數拼起來,加上密鑰,MD5一下,完事。 我們照做了。列表介面能用。查詢介面能用。建立…

你調一個第三方API,簽名死活不對——然後你發現文件根本沒寫清楚
這是一個真實故事。今天下午,我們在對接一個DNS管理平台的API,需要通過API自動建立DNS記錄。API文件寫著:「使用MD5簽名驗證」。
聽起來很簡單對吧?把參數拼起來,加上密鑰,MD5一下,完事。
我們照做了。列表介面能用。查詢介面能用。建立記錄——簽名錯誤。
反覆檢查了兩個小時。
API簽名的三種常見模式
在聊我們踩的坑之前,先科普一下:API簽名驗證大致分三種套路。
模式一:密鑰追加型(最常見)
這是最直覺的方式,也是大多數國內API的選擇。
sign = md5(param1=value1¶m2=value2 + secretKey)
把所有參數按字母排序拼成字串,然後在末尾追加密鑰,整體做MD5。微信支付、支付寶開放平台基本都是這個路子。
優點是簡單直觀,缺點是密鑰直接參與雜湊,如果雜湊演算法被攻破(MD5理論上已經不夠安全),密鑰有洩露風險。
模式二:HMAC型(最安全)
sign = HMAC-SHA256(secretKey, param1=value1¶m2=value2)
AWS、Google Cloud、Azure用的都是這種。密鑰作為HMAC的key,不直接拼進字串裡。
安全性最高,但實現複雜度也最高——你需要處理canonicalized request、timestamp、nonce等一堆東西。AWS Signature V4的文件長到能當枕頭。
模式三:密鑰參與排序型(最陰間)
sign = md5(所有參數INCLUDING secretKey一起按字母排序拼接)
注意區別:這裡密鑰不是追加在末尾,而是作為一個普通參數,和其他參數一起參與字母排序。
舉個例子,如果你的參數是:
domain=example.com
line=default
secretKey=abc123
top=A
value=1.2.3.4
簽名字串是:domain=example.com&line=default&secretKey=abc123&top=A&value=1.2.3.4
而不是:domain=example.com&line=default&top=A&value=1.2.3.4abc123
看到區別了嗎?第一種,secretKey排在line和top之間(按字母序s在l和t之間)。第二種,secretKey追加在最後。
這就是坑我們半天的地方。
為什麼列表介面能用但建立介面不行?
這是最精妙的部分。
列表介面(Record.List)參數很少,大概就三四個。碰巧這些參數的首字母排序後,secretKey正好排在最後面。所以不管你是「追加在末尾」還是「參與排序」,簽名結果是一樣的。
純屬巧合。
但建立介面(Record.Create)參數有七八個,其中有些參數的首字母在s後面(比如top、value)。這時候,兩種演算法的簽名結果就不同了。
這種「部分介面能用、部分不能用」的情況是最難排查的——因為你會以為自己的簽名邏輯是對的(畢竟列表介面驗證通過了),然後把時間浪費在檢查參數格式、編碼方式、HTTP headers等完全不相關的地方。
怎麼破?
最後解決方案很簡單:找到API的Swagger/OpenAPI文件,仔細看簽名說明,發現了那行關鍵的小字——「secretKey作為普通參數參與排序」。
幾個經驗教訓:
- 別猜簽名演算法。哪怕「大概知道是MD5簽名」,具體拼接方式不看文件就是賭運氣。
- 一個介面通過不代表簽名邏輯正確。要用參數最多的介面驗證,不要用參數最少的。
- 找Swagger先。很多平台的主文件寫得一塌糊塗,但Swagger定義是機器產生的,反而更準確。
- 列印簽名字串。不要只看最終的MD5值,把簽名前的原始字串印出來逐字元比對。
- 特別注意整數和字串的區別。Swagger裡標註int32的欄位,在簽名字串裡可能需要用「0」而不是0。型別不匹配就是簽名不對。
為什麼這個坑值得寫一篇文章?
因為這是一類極其常見但很少被討論的問題。
大廠的API文件(AWS、Google、Stripe)寫得非常詳細,簽名演算法有完整的範例和SDK。但大量的中小平台——特別是國內的安全產品、CDN服務、雲端主機廠商——文件品質參差不齊。簽名部分往往就一句話:「使用MD5簽名」,具體怎麼拼,不說。
而簽名驗證又是API安全的基礎。搞不定簽名,後面所有業務邏輯都無從談起。
所以下次你遇到「簽名錯誤」的時候,別急著懷疑自己的程式碼。先問三個問題:
- 密鑰是追加在末尾,還是參與排序?
- 有沒有Swagger/OpenAPI文件可以參考?
- 你驗證簽名用的是參數最多的介面嗎?
這三個問題能幫你省掉90%的排查時間。
本文基於小火龍實驗室的真實踩坑經歷。我們在對接DNS管理API時被簽名演算法折騰了半天,最終通過Swagger文件找到了答案。希望這篇文章能幫到同樣在和第三方API搏鬥的你。