HMAC 政策

本頁適用於 ApigeeApigee Hybrid

查看 Apigee Edge 說明文件。

政策圖示

這項政策會計算並視需要驗證雜湊架構訊息驗證碼 (HMAC)。HMAC 有時稱為「金鑰式訊息驗證碼」或「金鑰式雜湊」,它會使用 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 或 MD-5 等加密編譯雜湊函式,並將這些函式與密鑰一併套用至「訊息」,以產生該訊息的簽名或訊息驗證碼。此處的「訊息」一詞是指任何位元組串流。在 HMAC 的一般用途中,郵件寄件者會將郵件和 HMAC 傳送給收件者,而收件者可以使用 HMAC 和共用密鑰來驗證郵件。

這項政策是標準政策,可部署至任何環境類型。如要瞭解政策類型和各環境類型的可用性,請參閱「政策類型」。

如要進一步瞭解 HMAC,請參閱「HMAC:用於訊息驗證的金鑰雜湊」(rfc2104)。

範例

產生 HMAC

<HMAC name='HMAC-1'>

  <Algorithm>SHA256</Algorithm>

  <!-- the default encoding of the SecretKey is UTF-8 -->
  <SecretKey encoding='base64' ref='private.secretkey'/>

  <IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables> <!-- optional -->

  <!--
    The Message element accepts a template, which means the "message" the policy operates
    on can include fixed and multiple variable parts, including newlines and static functions.
    Whitespace, such as newlines and space characters, is significant.
   -->
  <Message>Fixed Part
{a_variable}
{timeFormatUTCMs(timeFormatString1,system.timestamp)}
{nonce}</Message>

  <!-- default encoding is base64 -->
  <Output encoding='base16'>name_of_variable</Output>

</HMAC>

驗證 HMAC

<HMAC name='HMAC-1'>

  <Algorithm>SHA256</Algorithm>

  <!-- the default encoding of the SecretKey is UTF-8 -->
  <SecretKey encoding='base16' ref='private.secretkey'/>

  <IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables> <!-- optional -->

  <!--
     The Message element accepts a template. This policy verifies an HMAC on the request content.
   -->
  <Message>{request.content}</Message>

  <!--
    VerificationValue is optional.
    Include it to perform an HMAC check.
  -->
  <VerificationValue encoding='base16' ref='expected_hmac_value'/>

  <!-- default encoding of the output is base64 -->
  <Output encoding='base16'>name_of_variable</Output>

</HMAC>

計算簽章和驗證簽章的程序完全相同。HMAC 政策會計算 HMAC,並可視需要驗證計算出的簽名是否符合預期值。選用的 VerificationValue 元素 (如有) 會引導政策檢查計算值是否符合已知或指定的值。


HMAC 的元素參照

政策參考資料說明 HMAC 政策的元素和屬性。

套用至頂層元素的屬性

<HMAC name="HMAC" continueOnError="false" enabled="true" async="false">

以下屬性適用於所有政策父元素。

屬性 說明 預設 在家狀態
名稱 政策的內部名稱。您可以在名稱中使用的字元僅限: A-Z0-9._\-$ %。不過,Apigee UI 會強制執行其他限制,例如自動移除非英數字元的字元。

您可以選擇使用 <DisplayName> 元素,在 Apigee UI 代理程式編輯器中為政策加上不同自然語言的名稱標籤。

不適用 必填
continueOnError 將其設為 false,即可在政策失敗時傳回錯誤。這是大多數政策的預期行為。

將其設為 true,即使政策失敗,流程執行作業仍會繼續進行。另請參閱:

false 選用
已啟用 設為 true 即可強制執行政策。

將其設為 false 可「關閉」政策。即使政策仍附加至流程,也不會強制執行。

選用
非同步 此屬性已淘汰。 false 已淘汰

<Algorithm>

<Algorithm>algorithm-name</Algorithm>

指定在計算 HMAC 時要使用的雜湊演算法。

預設 不適用
在家狀態 必填
類型 字串
有效值 SHA-1SHA-224SHA-256SHA-384SHA-512MD-5

政策設定可接受不區分大小寫的演算法名稱,字母和數字之間可以有或沒有連字號。例如 SHA256SHA-256sha256 是等價的。

<DisplayName>

<DisplayName>Policy Display Name</DisplayName>

除了使用名稱屬性,您也可以在 Apigee UI 代理程式編輯器中使用其他自然語言名稱標示政策。

預設 如果省略這個元素,系統會使用政策的 name 屬性值。
在家狀態 選用
類型 字串

<Message>

<Message>message_template_here</Message>
or
<Message ref='variable_here'/>

指定要簽署的訊息酬載。這個元素的輸入內容支援訊息範本 (變數替換),可在執行階段加入其他項目,例如時間戳記、Nonce、標頭清單或其他資訊。例如:

<Message>Fixed Part
    {a_variable}
    {timeFormatUTCMs(timeFormatString1,system.timestamp)}
    {nonce}
</Message>

訊息範本可包含固定和可變的部分,包括換行符號和靜態函式。空格字元 (例如換行符號和空格字元) 很重要。

預設 不適用
在家狀態 必填
類型 字串
有效值 任何字串皆可做為文字值。如果您提供 ref 屬性,系統會優先採用該屬性,而非文字值。政策會將文字值或參照的變數評估為訊息範本。

<輸出>

<Output encoding='encoding_name'>variable_name</Output>

指定政策應使用計算的 HMAC 值設定的變數名稱。並指定輸出內容要使用的編碼。

預設

預設輸出變數為 hmac.POLICYNAME.output

encoding 屬性的預設值為 base64

在家狀態 (選用步驟) 如果沒有這個元素,政策會使用 Base64 編碼值設定流程變數 hmac.POLICYNAME.output
類型 字串
有效值

編碼:hexbase16base64base64url

這些值不區分大小寫;hexbase16 是同義字。

Output 元素的文字值可以是任何有效的流程變數名稱。

<SecretKey>

<SecretKey encoding='encoding_name' ref='private.secretkey'/>

指定用於計算 HMAC 的密鑰。系統會從參照的變數取得索引鍵,並根據特定編碼進行解碼。

預設

參照的變數沒有預設值,因此必須使用 ref 屬性。

如果沒有 encoding 屬性,政策會根據預設使用 UTF-8 解碼密鑰字串,以取得金鑰位元組。

在家狀態 必填
類型 字串
有效值

encoding 的有效值為 hexbase16base64utf8。預設為 UTF8。值不區分大小寫,且連字號不具意義。Base16base-16bAse16 相同。Base16Hex 是同義詞。

使用編碼屬性可讓您指定包含 UTF-8 可列印字元範圍以外位元組的索引鍵。舉例來說,假設政策設定包含以下內容:

 <SecretKey encoding='hex' ref='private.encodedsecretkey'/>

假設 private.encodedsecretkey 儲存字串 536563726574313233

在這種情況下,系統會將鍵位元組解碼為:[53 65 63 72 65 74 31 32 33] (每個位元組以十六進位表示)。舉另一個例子來說,如果使用 encoding='base64',而 private.encodedsecretkey 則會保留字串 U2VjcmV0MTIz,則會產生相同的位元組組合。如果沒有編碼屬性,或是編碼屬性為 UTF8,字串值 Secret123 會產生相同的位元組組合。這裡顯示三種不同的方法,用來表示相同的鍵。

<VerificationValue>

<VerificationValue encoding='encoding_name' ref='variable_name'/>
or
<VerificationValue encoding='encoding_name'>string_value</VerificationValue>

(選用) 指定驗證值,以及用於編碼驗證值的編碼。政策會使用這個編碼來解碼值。

預設 沒有預設驗證值。如果元素存在,但 encoding 屬性不存在,政策會使用預設的 base64 編碼
在家狀態 選用
類型 字串
有效值

編碼屬性的有效值為:hexbase16base64base64url。這些值不區分大小寫;hexbase16 是同義詞。

VerificationValue 的編碼不必與 Output 元素使用的編碼相同。

<IgnoreUnresolvedVariables>

<IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables>

如果您希望政策在無法解析政策中指定的任何參照變數時擲回錯誤,請將此值設為 false。將其設為 true,即可將任何無法解析的變數視為空字串 (空值)。

IgnoreUnresolvedVariables 布林值只會影響訊息範本參照的變數。雖然 SecretKeyVerificationValue 可以參照變數,但這兩者都需要可解析,因此 ignore 設定不適用於這兩者。

預設
在家狀態 選用
類型 布林值
有效值 是或否

流程變數

政策可以在執行期間設定這些變數。

變數 說明 範例
hmac.policy_name.message 這個變數會根據有效訊息 (評估 Message 元素中指定的訊息範本結果) 來設定政策。 hmac.HMAC-Policy.message = "Hello, World"
hmac.policy_name.output Output 元素未指定變數名稱時,會取得 HMAC 運算的結果。 hmac.HMAC-Policy.output = /yyRjydfP+fBHTwXFgc5AZhLAg2kwCri+e35girrGw4=
hmac.policy_name.outputencoding 取得輸出編碼的名稱。 hmac.HMAC-Policy.outputencoding = base64

一般問題

從某個層面來看,HMAC 政策似乎很簡單:提供金鑰和訊息,並在回應中取得計算的 HMAC。如果您針對已知的訊息和金鑰組合取得意外的 HMAC 值,使用這項政策時可能會感到挫折。本節將說明一些使用注意事項,協助您解決這類問題。

驗證期間會出現兩個常見的陷阱,導致 HMAC 不相符:訊息中的空白字元差異,以及編碼和解碼的差異。後者適用於 SecretKey 元素Output 元素

空白字元差異

有些差異對人類來說可能不重要,但會影響輸出的 HMAC 值。舉例來說,假設密鑰可表示為「Secret123」。使用 UTF-8 解碼時,主要位元組會是:[53 65 63 72 65 74 31 32 33]。使用該金鑰計算訊息 abc 上的 HMAC-SHA256,結果會產生 a7938720fe5749d31076e6961360364c0cd271443f1b580779932c244293bc94。在訊息中加入一個空格,使其變成 abc<SPACE>,其中 <SPACE> 表示 ASCII 32,會產生 274669b2a85d2532da48e2ce3d8e52ee17346d1bcd1a606d87db1934b5ab294b 的 HMAC-SHA256。

同樣地,如果訊息為 abc<NEWLINE>,其中 <NEWLINE> 表示 ASCII 10,則 HMAC 為 0780370844ca07f896066837e8230d3b6a775f678a4ae03e6b5e864c674831f5。訊息稍有變動,就會產生截然不同的 HMAC 值。這是正常的設計。這是 HMAC 預期的行為。

重點摘要:請務必確保用於計算原始 HMAC 的訊息主體,與用於驗證 HMAC 的訊息主體完全相同。如果 HMAC 驗證者以任何方式變更訊息酬載 (例如新增空白或重新格式化文字),計算出的 HMAC 就會變更。

在政策設定中使用訊息範本時,請特別小心。舉例來說,下列政策設定片段顯示了潛在的問題:

<HMAC name='HMAC-1'>
    ...
    <!-- the result of this message template will include surrounding whitespace -->
    <Message>
        {request.content}
    </Message>
    ...
       
</HMAC>

評估 <Message> 元素內的訊息範本結果時,會在訊息內容周圍加入換行符號和空格。這可能不是預期的結果。較佳的設定如下所示:

<HMAC name='HMAC-1'>
    ...
    <Message>{request.content}</Message>
    ...
         
</HMAC>

編碼差異

同一個關鍵素材的不同解碼方式會產生不同的金鑰。假設密鑰可表示為「U2VjcmV0S2V5MTIz」。使用 UTF-8 解碼時,以 16 進制表示的鍵位元組會是:[55 32 56 6a 63 6d 56 30 53 32 56 35 4d 54 49 7a]。使用 Base64 解碼時,金鑰位元組會是 [53 65 63 72 65 74 4b 65 79 31 32 33]。以不同的方式解碼來源素材會產生不同的金鑰,進而產生不同的 HMAC 值。

重點摘要:請務必確保用於計算原始 HMAC 的金鑰內容,與用於驗證 HMAC 的金鑰完全相同。這可能表示您必須確保兩端都使用相同的金鑰編碼。在 HMAC 政策中,您可以使用 SecretKey 元素encoding 屬性指定金鑰編碼。

也請考慮輸出內容的編碼。以 27f17e11c8ece93844c5eb5e55161d993368628a214f9a51c25d0185e8ea06e2 表示的十六進位編碼 HMAC-SHA256 與以 J/F+Ecjs6ThExeteVRYdmTNoYoohT5pRwl0BhejqBuI= 表示的 Base64 編碼 HMAC-SHA256 相同。雖然兩者看起來不同,但這兩個字串代表相同的值。請確認使用相同的編碼來編碼原本計算的 HMAC 和驗證 HMAC。在 HMAC 政策中,您可以使用 Output 元素encoding 屬性,指定所需的輸出編碼,並在 VerificationValue 元素上使用相同的屬性,指定驗證器的解碼方式。

錯誤參考資料

本節說明這項政策觸發錯誤時,Apigee 傳回的錯誤代碼和錯誤訊息,以及 Apigee 設定的錯誤變數。如果您要開發錯誤處理規則,就必須瞭解這項資訊。如需更多資訊,請參閱「關於政策錯誤的相關資訊」和「處理錯誤」。

執行階段錯誤

政策執行時可能會發生這些錯誤。

錯誤代碼 HTTP 狀態 發生時機
steps.hmac.UnresolvedVariable 401

如果 HMAC 政策中指定的變數為下列任一情況,就會發生這項錯誤:

  • 超出範圍 (無法在執行政策的特定流程中使用)

  • 無法解析 (未定義)
steps.hmac.HmacVerificationFailed 401 HMAC 驗證失敗;提供的驗證值與計算值不符。
steps.hmac.HmacCalculationFailed 401 政策無法計算雜湊式訊息驗證碼 (HMAC)。
steps.hmac.EmptySecretKey 401 密鑰變數的值為空白。
steps.hmac.EmptyVerificationValue 401 儲存驗證值的變數為空白。

部署錯誤

部署含有這項政策的 Proxy 時,可能會發生這些錯誤。

錯誤名稱 HTTP 狀態 發生時機
steps.hmac.MissingConfigurationElement 401 缺少必要元素或屬性時,就會發生這項錯誤。
steps.hmac.InvalidValueForElement 401 如果 Algorithm 元素中指定的值不是下列任一值:SHA-1SHA-224SHA-256SHA-512MD-5,就會發生此錯誤。
steps.hmac.InvalidSecretInConfig 401 如果為 SecretKey 明確提供文字值,就會發生這個錯誤。
steps.hmac.InvalidVariableName 401 如果 SecretKey 變數不含 private 前置字串 (private.),就會發生這個錯誤。

錯誤變數

系統會在發生執行階段錯誤時設定這些變數。如需更多資訊 請參閱注意事項 政策錯誤。

變數 地點 範例
fault.name="fault_name" fault_name 是錯誤的名稱,如 上方的「執行階段錯誤」表格。錯誤名稱是最後一個 部分錯誤 fault.name Matches "UnresolvedVariable"
hmac.policy_name.failed 這項政策會在發生錯誤時設定這個變數。 hmac.HMAC-Policy.failed = true

錯誤回應範例

針對錯誤處理,最佳做法是將錯誤的 errorcode 部分加以包裝 回應。請勿參考 faultstring 中的文字,因為可能會變動。

錯誤規則範例

<FaultRules>
    <FaultRule name="HMAC Policy Errors">
        <Step>
            <Name>AM-Unauthorized</Name>
            <Condition>(fault.name Matches "HmacVerificationFailed")</Condition>
        </Step>
        <Condition>hmac.HMAC-1.failed = true</Condition>
    </FaultRule>
</FaultRules>