HMAC ポリシー

このページの内容は ApigeeApigee ハイブリッドに該当します。

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

次の属性は、すべてのポリシーの親要素に共通です。

属性 説明 デフォルト 要否
name ポリシーの内部名。名前に使用できる文字は A-Z0-9._\-$ % のみです。ただし、Apigee UI には追加の制限があり、たとえば、英数字以外の文字は自動的に削除されます。

必要に応じて、<DisplayName> 要素を使用して、Apigee UI プロキシ エディタでポリシーに別の自然言語名でラベルを付けます。

なし 必須
continueOnError ポリシーが失敗したときにエラーを返す場合は、false に設定します。これは、ほとんどのポリシーで想定される動作です。

ポリシーが失敗した後もフローの実行を続行する場合は、true に設定します。関連項目:

false 省略可
有効 ポリシーを適用するには、true に設定します。

ポリシーを無効にするには、false に設定します。ポリシーがフローに接続されている場合でも適用されません。

true 省略可
非同期 この属性は非推奨となりました。 false 非推奨

<Algorithm>

<Algorithm>algorithm-name</Algorithm>

HMAC の計算に使用するハッシュ アルゴリズムを指定します。

デフォルト 該当なし
要否 必須
文字列
有効な値 SHA-1SHA-224SHA-256SHA-384SHA-512MD-5

ポリシー構成で受け入れられるアルゴリズム名では、大文字小文字の区別や、文字と数字の間にダッシュがあるかないかの区別はありません。たとえば、SHA256SHA-256sha256 は同等です。

<DisplayName>

<DisplayName>Policy Display Name</DisplayName>

name 属性に加えて、Apigee UI プロキシ エディタでポリシーを別の自然言語名でラベル付けするために使用します。

デフォルト この要素を省略した場合、ポリシーの name 属性の値が使用されます。
要否 省略可
文字列

<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 です。

要否 省略可。この要素が存在しない場合、ポリシーは base64 でエンコードされた値を使用してフロー変数 hmac.POLICYNAME.output を設定します。
文字列
有効な値

エンコードの場合、hexbase16base64base64url

値の大文字と小文字は区別されません。hexbase16 は類義語です。

Output 要素のテキスト値は、任意の有効なフロー変数名となります。

<SecretKey>

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

HMAC の計算に使用する秘密鍵を指定します。この鍵は参照先の変数から取得され、特定のエンコードに従ってデコードされます。

デフォルト

参照先の変数にデフォルト値はありません。ref 属性が必要です。

encoding 属性がない場合、ポリシーはデフォルトで秘密鍵文字列を UTF-8 でデコードして鍵のバイト数を取得します。

要否 必須
文字列
有効な値

encoding の有効な値は、hexbase16base64utf8 です。デフォルト値は UTF-8 です。値の大文字と小文字は区別されず、ダッシュは無効な文字と判断されます。Base16 は、base-16bAse16 と同じです。Base16Hex は類義語です。

エンコード属性を使用すると、UTF-8 の印刷可能な文字の範囲外のバイト数を含む鍵を指定できます。たとえば、次のような構成をポリシー構成に含めるとします。

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

また、private.encodedsecretkey が文字列 536563726574313233 を保持しているとします。

この場合、鍵のバイト数は [53 65 63 72 65 74 31 32 33] のようにデコードされます(各バイト数は 16 進数で表されます)。別の例として、encoding='base64' を使用し、private.encodedsecretkey が文字列 U2VjcmV0MTIz を保持する場合、鍵のバイト数の組み合わせは同じになります。エンコード属性がない場合、またはエンコード属性 UTF8 がある場合、文字列値 Secret123 は同じバイト数の組み合わせになります。これは、同じ鍵を表す方法が 3 種類あることを示しています。

<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 に設定すると、解決できない変数を空の文字列(null)として扱います。

IgnoreUnresolvedVariables ブール値は、メッセージ テンプレートで参照される変数にのみ影響します。SecretKeyVerificationValue は変数を参照できますが、両方とも解決可能である必要があるため、ignore 設定はそれらには適用されません。

デフォルト false
要否 省略可
ブール値
有効な値 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 の不一致を生じさせる一般的な落とし穴は 2 つあります。それは、メッセージ内の空白文字の違いと、エンコードとデコードの違いです。後者は、SecretKey 要素Output 要素の両方に当てはまります。

空白文字の違い

出力 HMAC 値は、人間が些細に感じるような違いの影響を受けます。たとえば、「Secret123」として表すことができる秘密鍵があるとします。UTF-8 デコードの場合、キーバイトは [53 65 63 72 65 74 31 32 33] になります。このキーを使用してメッセージ abc に対する HMAC-SHA256 を計算すると、a7938720fe5749d31076e6961360364c0cd271443f1b580779932c244293bc94 になります。メッセージにスペースを 1 つ追加して abc<SPACE> にする(<SPACE> は ASCII 32 を意味します)と、HMAC-SHA256 は 274669b2a85d2532da48e2ce3d8e52ee17346d1bcd1a606d87db1934b5ab294b になります。

同様に、メッセージを 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 または hex エンコードで 27f17e11c8ece93844c5eb5e55161d993368628a214f9a51c25d0185e8ea06e2 と表現される HMAC-SHA256 と、base64 エンコード形式で J/F+Ecjs6ThExeteVRYdmTNoYoohT5pRwl0BhejqBuI= と表現される HMAC-SHA256 は同じです。この 2 つの文字列は異なっているように見えますが、同じ値を表します。最初に計算された HMAC と検証対象の HMAC で、同じエンコードを確実に使用してください。HMAC ポリシーでは、Output 要素encoding 属性を使用して目的の出力エンコードを指定したり、VerificationValue 要素にある同じ属性を使用して検証ツールのデコード方法を指定したりできます。

エラー リファレンス

このセクションでは、このポリシーによってエラーがトリガーされたときに返される障害コードとエラー メッセージ、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 検証値を格納する変数が空です。

デプロイエラー

以下のエラーは、このポリシーを含むプロキシをデプロイするときに発生することがあります。

エラー名 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>