HMAC-SHA256 標籤是一個 32 位元組的金鑰雜湊輸出,透過將共用秘密金鑰與訊息的精確位元組結合,經由 SHA-256 壓縮函式計算得出,然後產生一個固定的 64 字元十六進位字串,或是一個 44 字元的 Base64 字串,讓持有相同金鑰的驗證端可以重新計算,以確認訊息未被竄改。NIST FIPS 198-1 所定義的構造會將秘密同時混入內層與外層雜湊中,因此秘密本身永遠不會出現在摘要裡。輸出是確定性的:任何知道相同秘密、並將相同位元組序列輸入演算法的端點,都必定會得到相同的標籤。HMAC 並不會加密訊息 —— 任何看到明文的人仍然可以讀取它,任何得知秘密的人也可以偽造有效的標籤,因此金鑰處理方式才是真正決定安全性的關鍵。當任務是使用已知金鑰產生 HMAC-SHA256 標籤時,實際的工作在於確保輸入位元組完全正確,並選擇接收端可接受的編碼方式。

HMAC-SHA256 標籤究竟是什麼
HMAC 代表金鑰雜湊訊息驗證碼。它以一個底層雜湊函式(此處為 SHA-256)為基礎,搭配兩個衍生金鑰:一個在雜湊前混入訊息,另一個在雜湊後混入結果。NIST FIPS 198-1 中所發布的定義,使該構造在底層雜湊仍具備碰撞抗性或偽隨機性時,可被證明是安全的。無論訊息大小為何,HMAC-SHA256 標籤永遠恰好是 32 位元組:一個單一字元的訊息與一個數百萬位元組的訊息,都會產生相同的 64 字元十六進位輸出。
這個標籤同時證明了兩件事。第一,持有秘密的驗證端可以從接收到的位元組重新計算標籤並確認相符,藉此證明位元組在傳輸過程中未被竄改。第二,任何能夠算出相符標籤的人,必定知道該秘密,這就驗證了傳送端的身份。標籤無法證明的是機密性 —— 在所有常見的協定中,明文訊息與標籤會一起傳輸,任何攔截到這對資料的人仍然可以看到明文內容。
第三個值得注意的特性是,標籤並非單純的訊息雜湊。兩則明文相近的訊息會產生完全無關的標籤,因為秘密素材在每一步都被混入,因此該輸出無法作為未共享秘密之雙方所交換訊息的指紋來使用。HMAC 標籤因此屬於驗證與完整性機制,而非公開雜湊。
選擇正確的雜湊與輸入模式
演算法的選擇來自接收系統,而非個人偏好。使用 HS256 的 JWT 需要 HMAC-SHA256;新版區域的 AWS Signature v4 使用 HMAC-SHA256;部分 API 與 IoT 協定則指定 SHA-384 或 SHA-512。若在協定要求上述其中之一時更換雜湊,所產生的標籤會被接收端拒絕,因此第一個決策是閱讀協定規格,確認它預期的是完整長度的 HMAC-SHA256 標籤。
下一個決策是金鑰與訊息的編碼方式。UTF-8 模式將輸入視為 Unicode 文字,其中看起來理所當然的字串 "café" 實際上是 5 個位元組,而表情符號如 🛡 則各佔 4 個位元組。十六進位模式僅接受偶數個 0–9 與 a–f 字元,並將其解碼為欄位的字面位元組;它會拒絕 "0x" 前綴、內部空格、冒號以及奇數的半位元組數,因此一個不小心混入的格式字元不會悄悄改變協定的值。每個解碼後的欄位上限為 1,000,000 位元組,介面會拒絕空金鑰與空訊息以避免誤觸。HMAC 產生器為金鑰與訊息都提供這些模式,且兩者可獨立選擇。
金鑰與訊息可以分別使用不同的模式。一個常見的模式是將已公布的測試向量以十六進位位元組輸入,而訊息則是純 UTF-8 文字;或是輸入人類可讀的金鑰,而訊息則來自二進位協定欄位。唯一的規則是位元組一致性:接收端將送入 HMAC 的位元組,必須與此處輸入的位元組一致,不能有多餘的空白、結尾換行,或前置識別符。
如何產生 HMAC-SHA256 標籤
- 確認協定預期的是完整的 HMAC-SHA256 標籤(32 位元組)而非截斷值,然後在工具中選擇 SHA-256。
- 輸入秘密金鑰。若金鑰為人類可讀文字,請切換為 UTF-8 模式;若為二進位或已公布的金鑰,請切換為十六進位模式 —— 貼上精確的位元組,不可包含 0x 前綴、冒號或空格。
- 輸入接收端將進行雜湊的訊息。訊息的 UTF-8 或十六進位選擇,與金鑰的模式相互獨立;若協定會對空白進行標準化,請在貼上前套用該規則。
- 點擊產生。HMAC 產生器會在同一個步驟中將完整標籤分別以小寫十六進位與標準填充式 Base64 呈現,因此兩種編碼皆可取得,無需重新輸入任何資料。
- 複製協定所要求的編碼。記錄檔、命令列工具與大多數 API 使用十六進位;HTTP 標頭、JWT 與重視簡潔性的環境則使用 Base64。
- 請勿截斷標籤、加上版本或演算法前綴,也不要切換為 Base64url,除非接收系統明確記載該需求 —— 視覺上相似的字串並無法互換。
安全地讀取與分享輸出
十六進位與 Base64 並非不同的標籤,而是同一個 32 位元組的兩種呈現方式。十六進位形式為每個位元組兩個字元,因此 SHA-256 標籤永遠是 64 字元。Base64 形式則將 3 個位元組群組為 4 個字元,並填充為 4 的倍數,就 32 位元組的輸入而言,即為 44 字元,並在結尾帶有一個 '=' 填充字元。兩者之間的轉換是無損的,解碼後會產生相同的位元組。
無法互換的是標準 Base64 與 Base64url。URL 安全變體會將 '-' 取代為 '+',將 '_' 取代為 '/',並通常省略填充,因此為某一編碼設計的權杖,會被另一編碼的嚴格解碼器所拒絕。HMAC 產生器輸出的是標準填充式 Base64;只有在協定明確要求時,才轉換為 Base64url。同樣的注意事項也適用於前置輸出,例如字面的 "hmac-sha256=" 或 "v1." —— 這些是高階協定所附加的信封慣例,而非 HMAC 標籤本身的一部分。
操作衛生與位元組正確性同樣重要。請從適用於該協定的密碼學安全隨機來源產生金鑰素材,透過受保護的管道進行發布,依用途區分金鑰,並在疑似遭到破解時進行輪替。人類密碼的熵值過低,絕對不能直接使用 —— 當密碼必須轉為金鑰時,請將其通過協定所記載的密碼型 KDF(PBKDF2、bcrypt、scrypt 或 Argon2),並以衍生出的位元組作為 HMAC 金鑰。切勿將正式環境的秘密貼到共用或不受信任的裝置中,並一律在伺服器上使用常數時間函式,比對接收到的標籤與重新計算的標籤,避免時序旁路攻擊洩漏逐位元組的一致性。
為何不同工具產生的標籤會有差異
當兩個系統針對看似相同的輸入產生不同的標籤時,原因幾乎總是位元組層級的不一致,而非真正的互通性失敗。下列檢查清單涵蓋了任何一個多餘字元都可能改變結果的所有面向:
- 雜湊選擇 —— SHA-256、SHA-384 與 SHA-512 分別產生 32、48 與 64 位元組的標籤。
- 金鑰編碼 —— UTF-8 位元組與解碼後的十六進位位元組;同一個詞依據重音、標準化與多位元組字元的不同,可能會是不同的位元組序列。
- 訊息編碼 —— UTF-8 文字、十六進位位元組,或經 Base64 解碼的輸入,加上雜湊前所套用的空白與換行慣例。
- 標籤截斷 —— 即使兩者看起來有關聯,截斷為前 16 位元組的標籤是不同的值,且任何截斷方式都必須由協定明確指定。
- 輸出編碼 —— 標準 Base64 與 Base64url,或在接收端嚴格要求時的大寫與小寫十六進位。
HMAC 產生器已鎖定為八個符合 RFC 4231 的完整一致性標籤,涵蓋短金鑰、二進位重複位元組金鑰與資料、小於摘要長度的金鑰,以及跨越雜湊區塊邊界的資料。SHA-256 與 SHA-512 各針對四個獨立輸入進行驗證,介面並另外提供 WebCrypto 所定義的 SHA-384 選項。當接收端拒絕一個標籤時,最快的恢復一致性的做法是:先根據已公布的向量確認金鑰與訊息的精確位元組,接著比對演算法與輸出編碼。
雜湊變體比較
| 雜湊 | 輸出位元組 | 十六進位長度 | Base64 長度 | 常見用途 |
|---|---|---|---|---|
| SHA-256 | 32 | 64 | 44 | JWT HS256、AWS Signature v4 |
| SHA-384 | 48 | 96 | 64 | 高保證需求協定 |
| SHA-512 | 64 | 128 | 88 | 舊版伺服器與 64 位元原生程式碼 |
瀏覽器端的實作會將所選的位元組匯入為一個不可匯出的 WebCrypto HMAC 金鑰,使用 subtle.sign 執行所選的雜湊,並將產生的標籤分別以小寫十六進位與標準填充式 Base64 呈現 —— 所有輸入皆保留於當前分頁中,永遠不會送至伺服器。
如果您正在權衡各種選項,在瀏覽器中依金鑰長度解密 Vigenere 密碼對此有詳細說明。
如果您正在權衡各種選項,HMAC 計算機:精確符合協定的位元組對此有詳細說明。