SheepDev

雜湊、ID與隨機數

Webhook 簽章不一致,如何檢查 HMAC 條件?

使用工具

Webhook 的 JSON 看起來正確,簽章檢查卻失敗。語意相同還不夠,因為 HMAC 計算的是金鑰與訊息位元組的組合。整理鍵順序或空白後的文字,可能已不是傳送方簽署的原文。這裡用可公開的練習金鑰逐項定位。

用已知金鑰和本文確認計算路徑

選擇 SHA-256、十六進位,金鑰輸入 key,本文輸入 The quick brown fox jumps over the lazy dog,不加額外空白。結果應如下。這是公開練習資料,不能當正式環境金鑰;先通過已知小例子,比只試真實請求更容易定位。

練習 HMAC-SHA-256
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

這不是本文的普通 SHA-256,也不是簡單拼接金鑰與本文再雜湊。協定規定 HMAC-SHA-256 就要使用該構造;SHA-384、SHA-512 也應查提供方規範,不憑簽章外觀猜測。

僅格式化 JSON 也會改變簽章

下面 JSON 含義相同,但空格、換行或鍵順序會改變 HMAC 的位元組輸入。驗證前先 parse 再 stringify 或格式化,可能無法重現傳送方本文。協定簽原始本文時,就必須保留原位元組驗證。

含義相同但位元組不同
{"amount":100,"currency":"JPY"}

{ "amount": 100, "currency": "JPY" }

LF 和 CRLF 也不同。追查 HTTP 函式庫、儲存、編輯器或複製在哪一步改變內容時,可查看位元組數和十六進位。二進位本文不能隨意轉文字;本工具區分檔案原位元組與 UTF-8 文字輸入。

看似相同的金鑰可能代表不同位元組

金鑰寫成 6b6579 時,要確認是六個文字字元,還是十六進位表示的三個位元組。後者解碼是 key,但本工具不會自動按十六進位解碼金鑰欄,而是使用 UTF-8 文字。Base64 金鑰也一樣,字面相同不一定表示正確的金鑰位元組。

不要把任意二進位金鑰轉成亂碼來強行輸入,應使用能接受準確位元組的本機實作或提供方 SDK。檢查簽發、儲存形式和讀取時解碼,比不斷換金鑰更有效。頁面的金鑰位元組數也能幫助發現多餘換行或漏解碼。

簽署對象未必只有本文

有些協定按固定順序組合時間、HTTP 方法、路徑和本文,僅輸入本文不會一致。需要核對分隔符、換行、URL 編碼及時間表示。本工具是通用 HMAC 計算,不會自動識別任意 Webhook 並建構簽署字串。

十六進位、Base64、Base64url 外觀不同。本頁面輸出前兩種,比較 Base64url 時須考慮表示差異。標頭可能帶 sha256= 前綴,但它未必屬於摘要;應按協定選擇比較部分,不能隨意刪字元湊一致。

HMAC 一致只是接收驗證的一部分

結果一致不能證明請求新鮮或未被重放。時間與 ID 的重放防護、比較實作、金鑰管理屬於接收端責任,本計算頁面不等於完整認證。排查時逐項固定演算法、金鑰表示、簽署位元組、輸出格式,才能追蹤變化影響。

共用重現案例應使用練習金鑰與虛構本文,不把正式環境秘密貼進聊天或工單。瀏覽器本機處理不消除螢幕共用和剪貼簿風險;洩漏後關閉頁面並不能解決,應遵循提供方或組織的金鑰更新流程。先用本例的公開 key 練習。

檢查是否用重組 JSON 取代了簽章原文

解析 JSON 後重新序列化再算 HMAC,可能改變鍵順序、空白、換行和跳脫寫法。結構相同與簽章位元組相同是兩種檢查。協定簽原始本文時應保留原文;為便於比較而格式化,可能改了比較對象。

先用公開已知金鑰和短已知本文,一次改一個條件。不一致就查演算法、輸出格式和金鑰解釋;已知例通過而真實資料失敗,再查原位元組和組裝。避免記錄秘密金鑰,先用編碼、長度等非秘密資訊。此欄把金鑰當 UTF-8 文字,不自動解碼十六進位。

MAC 一致不驗證重放防護。協定的時間戳、nonce 或事件 ID 可能還需接收方驗證和去重。HMAC 是共享金鑰認證計算,不是本文加密,應把簽章排查與安全單次處理設計分開。

參考資料

使用工具

指南 →