HMAC-SHA256 是一種金鑰雜湊訊息鑑別碼,結合 SHA-256 密碼雜湊演算法與共享秘密金鑰,產生一個 32 位元組的標籤,任何持有相同秘密且訊息位元組完全一致的一方都能重新計算出來。若要產生 HMAC-SHA256 簽章,請選擇 SHA-256,將秘密與訊息以精確的 UTF-8 文字或精確的十六進位位元組輸入,並以小寫十六進位或填補式 Base64 讀回完整標籤。此運作透過瀏覽器的 Web Cryptography API 執行,因此輸入內容永遠不會離開目前的分頁。位元組的一致性至關重要:多一個換行、夾帶空白、同一個字詞使用不同編碼,或是標籤被截斷,都會產生不同的簽章,並導致伺服器端的驗證失敗。標籤本身不會隱藏訊息;它僅能證明產生者持有該金鑰,且訊息位元組在傳輸過程中未被修改。對於 API webhook、簽章 URL、JWT 與類似協定,在產生簽章之前,務必直接從主導規格中讀取所需的雜湊、金鑰格式、訊息正規化方式與輸出編碼。

how to generate hmac sha256 signature
how to generate hmac sha256 signature

HMAC-SHA256 的作用與 API 採用它的原因

伺服器使用 HMAC-SHA256 來驗證連入請求,而不必將秘密透過網路傳送。用戶端將共享秘密與精確的請求位元組結合,計算出 32 位元組的標籤,並將其放入標頭中送出。伺服器端以自己的秘密副本重複計算,僅在兩個標籤相符時接受該請求。這證明了該請求來自金鑰的持有者,且傳輸過程中沒有任何位元組遭到竄改。常見的 HMAC-SHA256 應用場景,包括 Stripe、GitHub、Slack 等平台的 webhook 簽章、HS256 等 JWT HMAC 演算法、OAuth 1.0a 請求簽章,以及許多內部 REST API 慣例。這些協定都不會隱藏訊息本文;它們僅能證明其完整性與來源。

雜湊變體與標籤長度

HMAC 產生器支援三種底層雜湊演算法,而你遵循的協定會決定該選用哪一種。HMAC-SHA256 無論訊息長度為何,永遠會輸出 32 位元組;HMAC-SHA384 永遠會輸出 48 位元組;HMAC-SHA512 永遠會輸出 64 位元組。

HashTag length (bytes)Tag length (hex chars)Tag length (Base64 chars)
SHA-256326444
SHA-384489664
SHA-5126412888

若協定寫明「HMAC-SHA256」卻接受更長的標籤,代表前面附加了其他內容(通常是像「sha256=」這類的演算法識別字,或是時間戳記封套)。除非規格明確要求,否則請勿自行去除或填補標籤。

挑選精確的位元組:UTF-8 與十六進位

HMAC 產生器允許你分別為金鑰與訊息設定 UTF-8 或十六進位,因為實際協定常會以不同格式分別提供這兩個欄位。

  • UTF-8 模式會將輸入視為 Unicode 文字,並以 UTF-8 位元組序列編碼。字詞「café」會變成五個位元組(c、a、f,再加上佔兩個位元組的 é),中日韓字元各佔三個位元組,表情符號則各佔四個位元組。當協定將秘密與訊息以字串形式傳遞時,請使用 UTF-8 模式。
  • 十六進位模式要求偶數個十六進位數字,且不接受 0x 前綴、空格、冒號或奇數的半位元組。前置零會被保留:0a 是一個位元組,不等同於 a。針對已公布的測試向量、原始二進位欄位,以及規格中以位元組形式呈現的內容,請使用十六進位模式。每個解碼後的欄位上限為 1,000,000 位元組,因此超過此限制的承載資料會在計算標籤前遭到拒絕。

若僅其中一個欄位以十六進位記載,另一個以字串記載,請分別為各個輸入框切換模式。將十六進位字串貼入 UTF-8 模式時,系統會對該字串的字面 ASCII 字元進行雜湊(得到「6b 65 79」而非三個位元組的「key」),這幾乎從來不是協定預期的結果。

產生 HMAC-SHA256 簽章

  1. 開啟 HMAC 產生器,確認演算法選擇器顯示 SHA-256。除非你的協定明確要求 SHA-384 或 SHA-512,否則請勿變更。
  2. 設定金鑰編碼。若規格以字串形式提供秘密,請選擇 UTF-8;若以位元組形式標示秘密(例如 RFC 4231 中的 0b0b0b0b... 金鑰),請選擇十六進位。貼上金鑰時,不要附加額外空白、引號或 0x 前綴。
  3. 同樣地設定訊息編碼。針對人類可讀的請求本文、正規化字串、JSON 承載資料與查詢字串,請使用 UTF-8;針對二進位大型物件與已公布的測試向量,請使用十六進位。請嚴格保留規格所定義的位元組,包括結尾是否帶有換行。
  4. 產生標籤。HMAC 產生器會以同一個計算結果,同時以小寫十六進位與填補式標準 Base64 呈現完整的 32 位元組 SHA-256 結果。
  5. 複製協定要求的編碼。多數 webhook 預期十六進位,其他則預期標準 Base64,少數預期 Base64url。若規格要求 Base64url,請自行轉換顯示的 Base64:將 + 換成 -、將 / 換成 _,並去除結尾的 = 填補字元;標籤的位元組完全相同,僅字元集不同。
  6. 在將標籤用於生產環境之前,先以規格中的已知測試向量進行驗證。HMAC 產生器鎖定了八組完整的 RFC 4231 一致性標籤,因此若在已公布的向量上發生不一致,問題出在你的輸入位元組,而非計算過程。

不同工具間 HMAC-SHA256 簽章不一致的原因

當相同的秘密與相同的訊息在兩個系統中產生不同的標籤時,差異幾乎都來自下列其中一項:

  • 雜湊演算法錯誤。SHA-256、SHA-384 與 SHA-512 在相同輸入下會產生完全不同的標籤。請確認演算法選擇器與程式庫設定一致。
  • 編碼錯誤。UTF-8 文字「ñ」佔兩個位元組(0xC3 0xB1),而 Latin-1 的「ñ」佔一個位元組(0xF1)。對兩者進行雜湊會得到不同的標籤。字串開頭的 BOM 字元是常見且不易察覺的元凶。
  • 夾帶空白。JSON 承載資料中多一個換行、結尾的空格或定位字元,都會悄悄更改摘要結果。請依照規格要求,精確地正規化訊息。
  • 標籤截斷。部分舊有系統僅使用 HMAC-SHA256 標籤最左側的 16 位元組。現代協定要求使用完整的 32 位元組;除非規格明確規定,否則請勿自行截斷。
  • Base64url 與標準 Base64 混淆。標籤的位元組完全相同,僅字元集不同(+ 對應 -、/ 對應 _,以及填補規則不同)。任一形式解碼後都必須得到相同的 32 位元組。
  • 演算法前綴。像 sha256=abcdef... 這類標頭,會在字串前面附加一個字面標籤,該標籤屬於比對字串的一部分,並非標籤本身的一部分。請依照規格要求,精確地去除或保留前綴。

在認定秘密有誤之前,請先逐項檢視上述清單。在伺服器端,請使用常數時間函式比對標籤,以避免時序洩漏協助攻擊者猜測位元組,這也是 NIST FIPS 198-1 所建議的做法。

HMAC-SHA256 的金鑰管理

即使標籤計算再怎麼嚴謹,脆弱或管理不當的金鑰仍會破壞整個機制。請使用為該協定產生的高熵隨機資料(256 位元或更長的秘密為典型長度),透過受保護的管道(例如秘密管理工具或帶外佈建流程)進行分發;依用途區分不同金鑰,使 webhook 金鑰外洩時無法偽造 API 請求;並在疑似遭到破解時立即輪替。人類設定的密碼並不會自動成為強健的 HMAC 金鑰:若應用程式必須接受密碼,請使用協定明確指定的密碼型 KDF 與參數來衍生實際金鑰,而不是在用戶端直接對密碼進行雜湊。避免將生產環境的秘密貼入共用或不受信任的裝置;HMAC 產生器完全在瀏覽器中執行,不會將輸入內容傳送至任何地方,但借來的筆電終究還是借來的筆電。標籤比對一致,僅能證明兩方持有相同的秘密,並就訊息的精確位元組達成共識;它無法證明機密性,也無法防範金鑰外洩。

若你在評估各種選項,將純文字轉換為二進位:UTF-8 位元組演練對此有詳細說明。

若你在評估各種選項,Base100 編碼說明:位元組到表情符號的公式對此有詳細說明。