HMAC 政策

本頁內容適用於 ApigeeApigee Hybrid

查看 Apigee Edge 說明文件。

政策圖示

這項政策會計算雜湊式訊息驗證碼 (HMAC),並視需要進行驗證。HMAC 有時也稱為「金鑰訊息驗證碼」或「金鑰雜湊」,會使用加密編譯雜湊函式 (例如 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 或 MD-5) 處理「訊息」和密鑰,在該訊息上產生簽名或訊息驗證碼。這裡的「訊息」是指任何位元組串流。一般來說,訊息的傳送者會將訊息和 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 使用者介面會強制執行其他限制,例如自動移除非英數字元。

(選用) 使用 <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 代理項目編輯器中,以其他自然語言名稱標示政策。

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

<Message>

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

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

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

訊息範本可包含固定和可變動的部分,包括換行符號和靜態函式。 空白字元 (例如換行符號和空格字元) 具有意義。

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

<Output>

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

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

預設

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

encoding 屬性的預設值為 base64

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

編碼時,請使用 hexbase16base64base64url

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

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

<SecretKey>

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

指定用於計算 HMAC 的密鑰。這個鍵是從參照的變數取得,並根據特定編碼解碼。

預設

參照變數沒有預設值,因此必須提供 ref 屬性。

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

外觀狀態 必填
類型 字串
有效值

encoding 的有效值為 hexbase16base64utf8。預設值為 UTF8。值不區分大小寫,且連字號不重要。Base16base-16bAse16 相同。「Base16」和「Hex」是同義詞。

使用編碼屬性可指定包含 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 設定不適用於這些變數。

預設
外觀狀態 選用
類型 布林值
有效值 true 或 false

流程變數

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

變數 說明 範例
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 解碼時,以 base16 表示的鍵位元組為:[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 屬性,指定金鑰編碼。

也請考慮輸出內容的編碼。以 base16 或十六進位編碼表示的 HMAC-SHA256 (27f17e11c8ece93844c5eb5e55161d993368628a214f9a51c25d0185e8ea06e2) 與以 base64 編碼形式表示的 HMAC-SHA256 (J/F+Ecjs6ThExeteVRYdmTNoYoohT5pRwl0BhejqBuI=) 相同。這兩個字串看起來不同,但代表相同的值。請務必使用相同的編碼方式,編碼原始計算的 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 variables

These variables are set when a runtime error occurs. For more information, see What you need to know about policy errors.

Variables Where Example
fault.name="fault_name" fault_name is the name of the fault, as listed in the Runtime errors table above. The fault name is the last part of the fault code. fault.name Matches "UnresolvedVariable"
hmac.policy_name.failed The policy sets this variable in the case of a failure. hmac.HMAC-Policy.failed = true

Example error response

For error handling, the best practice is to trap the errorcode part of the error response. Do not rely on the text in the faultstring, because it could change.

Example fault rule

<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>