アンチパターン: API プロキシ内で複数値の HTTP ヘッダーに誤った方法でアクセスする

HTTP ヘッダーは名前と値のペアです。クライアント アプリケーションとバックエンド サービスはこれを使用して、リクエストとレスポンスそれぞれの追加情報を渡すことができます。次に、簡単な例をいくつか示します。

  • Authorization リクエスト ヘッダーは、ユーザーの認証情報をサーバーに渡します。
    Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
  • Content-Type ヘッダーは、送信されるリクエストまたはレスポンスのコンテンツ タイプを示します。
    Content-Type: application/json

HTTP ヘッダーはヘッダー フィールドの定義に応じて 1 つまたは複数の値を保持します。1 つのヘッダーが複数の値を保持する場合は、値がカンマで区切られます。次に、複数の値を保持するヘッダーの例を示します。

  • Cache-Control: no-cache, no-store, must-revalidate
  • Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
  • X-Forwarded-For: 10.125.5.30, 10.125.9.125

Apigee Edge では、フロー変数を使用することで、どの Edge ポリシーや条件フローからでもヘッダーに簡単にアクセスできます。次に、Edge で特定のリクエスト ヘッダーまたはレスポンス ヘッダーにアクセスするのに使用できる変数の一覧を示します。

フロー変数:

  • message.header.header-name
  • request.header.header-name
  • response.header.header-name
  • message.header.header-name.N
  • request.header.header-name.N
  • response.header.header-name.N

JavaScript オブジェクト:

  • context.proxyRequest.headers.header-name
  • context.targetRequest.headers.header-name
  • context.proxyResponse.headers.header-name
  • context.targetResponse.headers.header-name

次の AssignMessage ポリシーの例は、リクエスト ヘッダーの値を読み取り、この値を変数に保存する方法を示します。

<AssignMessage continueOnError="false" enabled="true" name="assign-message-default">
  <AssignVariable>
    <Name>reqUserAgent</Name>
    <Ref>request.header.User-Agent</Ref>
  </AssignVariable>
</AssignMessage>

アンチパターン

Edge ポリシー内で HTTP ヘッダー値にアクセスし、最初の値だけを返す方法は誤りです。この方法では、複数の値を持つ HTTP ヘッダーの場合に問題が生じる可能性があります。

以下に、ヘッダーにアクセスするいくつかの例を示します。

例 1: JavaScript コードを使用して、複数の値を持つ Accept ヘッダーを読み取る

Accept ヘッダーが、次のような複数の値を持つとします。

Accept: text/html, application/xhtml+xml, application/xml

次に、Accept ヘッダーから値を読み取る JavaScript コードの例を示します。

// Read the values from Accept header
var acceptHeaderValues = context.getVariable("request.header.Accept");

この JavaScript コードは、Accept ヘッダーから最初の値だけを返します(この例では text/html)。

例 2: AssignMessage または RaiseFault ポリシーで、複数の値を持つ Access-Control-Allow-Headers ヘッダーを読み取る

Access-Control-Allow-Headers ヘッダーが、次のような複数の値を持つとします。

Access-Control-Allow-Headers: content-type, authorization

次のコードは、Access-Control-Allow-Headers ヘッダーを設定する AssignMessage または RaiseFault ポリシーの一部分です。

<Set>
  <Headers>
    <Header name="Access-Control-Allow-Headers">{request.header.Access-Control-Request-Headers}</Header>
  </Headers>
</Set>

このコードでは、リクエスト ヘッダー Access-Control-Allow-Headers からの最初の値(この例では content-type)だけを使って Access-Control-Allow-Headers ヘッダーが設定されます。

影響

  1. 上記のどちらの例でも、複数の値を持つヘッダーから最初の値だけが返されることに注目してください。これらの値がその後、なんらかの関数やロジックを実行する目的で API プロキシフロー内の別のポリシーまたはバックエンド サービスで使用された場合、予期しない結果につながる可能性があります。
  2. リクエスト ヘッダー値が取得されてターゲット サーバーに渡される時点で、API リクエストがバックエンドによって不適切に処理され、誤った結果が生じる可能性があります。
  3. クライアント アプリケーションが Edge レスポンスからの特定のヘッダー値に依存している場合も、不適切な処理が行われ、誤った結果が生じる可能性があります。

ベスト プラクティス

  1. 適切な組み込みフロー変数を使用します(request.header.header_name.values.countrequest.header.header_name.Nresponse.header.header_name.values.countresponse.header.header_name.N)。

    次に、JavaScript または Java Callout ポリシー内で処理を繰り返し、特定の 1 つのヘッダーからすべての値を取得します。

    例: 複数の値を持つヘッダーを読み取る JavaScript コードの例

    for (var i = 1; i <=context.getVariable('request.header.Accept.values.count'); i++)
    {
      print(context.getVariable('request.header.Accept.' + i));
    }
    

    たとえば上記のコードでは、application/xml;q=0.9, */*;q=0.8 は 1 つの値のように見えます。

    区切り文字としてセミコロンを使ってヘッダー値を分割する必要がある場合は、string.split(";") を使用して値を区切ってください。

  2. RaiseFault または AssignMessage ポリシー内で、フロー変数 request.header.header_name.values に対して substring() 関数を実行することで、ヘッダー内のすべての値を読み取ります。

    例: 複数の値を持つヘッダーを読み取る RaiseFault または AssignMessage ポリシーの例

    <Set>
      <Headers>
       <Header name="Access-Control-Allow-Headers">{substring(request.header.Access-Control-Request-Headers.values,1,-1)}</Header>
      </Headers>
    </Set>
    

関連情報