リバース プロキシとそのバックエンド Web アプリケーションの間で、元の HTTP ホスト名を維持する

API Management
App Service
Application Gateway
Front Door
Spring Apps

Web アプリケーションの前面でリバース プロキシを使うときは、元の HTTP ホスト名を維持することをお勧めします。 バックエンド アプリケーション サーバーに提供されるものとは異なるホスト名をリバース プロキシで使うと、Cookie やリダイレクト URL が正しく機能しない可能性があります。 たとえば、セッション状態が失われたり、認証が失敗したり、バックエンド URL が誤ってエンド ユーザーに公開されたりすることがあります。 アプリケーション サーバーが Web ブラウザーと同じドメインを認識するように、初期要求のホスト名を保持することで、これらの問題を回避できます。

このガイダンスは、Azure App ServiceAzure Spring Apps など、サービスとしてのプラットフォーム (PaaS) オファリングでホストされるアプリケーションに特に当てはまります。 この記事では、よく使われるリバース プロキシ サービスである Azure Application GatewayAzure Front DoorAzure API Management に関する具体的な実装ガイダンスを提供します。

注意

Web API は、一般に、ホスト名の不一致によって発生する問題に対する影響をそれほど受けません。 シングルページ アプリとそのバックエンド API の間の通信をセキュリティ保護するために Cookie を使用する (たとえば、フロントエンド用バックエンドと呼ばれるパターン) 場合を除き、通常は Cookie に依存しません。 ODataHATEOAS のような特定の API スタイルを除き、多くの場合、Web API は絶対 URL をそれ自体に返しません。 API の実装が Cookie に依存している場合、または絶対 URL を生成する場合は、この記事で説明されているガイダンスが適用されます。

エンドツーエンドの TLS/SSL が必要な場合は (リバース プロキシとバックエンド サービスの間の接続で HTTPS が使用されている)、バックエンド サービスで元のホスト名に対応する TLS 証明書も必要になります。 この要件により、証明書を展開および更新するときの運用の複雑さが増しますが、多くの PaaS サービスでは、フル マネージドの無料の TLS 証明書が提供されています。

Context

HTTP 要求のホスト

多くの場合、アプリケーション サーバーまたは要求パイプライン内の一部のコンポーネントでは、ブラウザーがそれにアクセスするために使ったインターネット ドメイン名が必要になります。 これは、要求の "ホスト" です。 それは IP アドレスのこともありますが、通常は、contoso.com のような名前です (その場合、ブラウザーにより DNS を使って IP アドレスに解決されます)。 通常、ホストの値は要求 URI のホスト コンポーネントによって決定されます。これは、ブラウザーが Host HTTP ヘッダーとしてアプリケーションに送信します。

重要

セキュリティ メカニズムでホストの値を使用しないでください。 この値は、ブラウザーまたは他のユーザー エージェントによって提供され、エンド ユーザーが簡単に操作できます。

状況によっては (特に、要求チェーン内に HTTP リバース プロキシがある場合)、アプリケーション サーバーに到達する前に元のホスト ヘッダーが変更されることがあります。 リバース プロキシによってクライアント ネットワーク セッションが閉じられ、バックエンドへの新しい接続が設定されます。 この新しいセッションでは、クライアント セッションの元のホスト名を引き継ぐか、新しいものを設定することができます。 後者の場合でも、プロキシは、ForwardedX-Forwarded-Host のような他の HTTP ヘッダーで、元のホストの値を送信することがよくあります。 この値により、アプリケーションで元のホスト名を特定できますが、これらのヘッダーを読み取るようにコーディングされている場合に限られます。

Web プラットフォームでホスト名が使われる理由

マルチテナントの PaaS サービスでは、着信要求を適切なテナントのバックエンド サーバーにルーティングするために、登録および検証されたホスト名が必要になることがよくあります。 これは、通常、すべてのテナントに対する着信要求を受け入れるロード バランサーの共有プールがあるためです。 テナントでは、通常、着信ホスト名を使って、顧客テナントの正しいバックエンドが検索されます。

簡単に使い始めることができるように、これらのプラットフォームでは、通常、デプロイされたインスタンスにトラフィックをルーティングするように事前に構成された既定のドメインが提供されています。 App Service の場合、この既定のドメインは azurewebsites.net です。 ユーザーが作成した各 Web アプリは、独自のサブドメインを取得します (例: contoso.azurewebsites.net)。 同様に、Spring Apps の既定のドメインは azuremicroservices.io で、API Management の場合は azure-api.net です。

運用環境のデプロイでは、これらの既定のドメインは使用しません。 代わりに、組織またはアプリケーションのブランドに合わせて独自のドメインを提供します。 たとえば、contoso.com は App Service の contoso.azurewebsites.net Web アプリにバックグラウンドで解決できますが、Web サイトにアクセスするエンド ユーザーにこのドメインが見えてはなりません。 ただし、この contoso.com というカスタム ホスト名は PaaS サービスに登録する必要があるため、プラットフォームは要求に応答する必要があるバックエンド サーバーを識別できます。

Diagram that illustrates host-based routing in App Service.

アプリケーションがホスト名を使用する理由

アプリケーション サーバーでホスト名が必要になる一般的な 2 つの理由は、絶対 URL を作成するためと、特定のドメインの Cookie を発行するためです。 たとえば、アプリケーションのコードで次のことを行う必要がある場合です。

  • 相対 URL ではなく絶対 URL を HTTP 応答で返します (ただし、一般に、Web サイトは可能な場合は相対リンクをレンダリングする傾向があります)。
  • Web サイトへのリンクをユーザーにメールで送信する場合のように、相対 URL を使用できない HTTP 応答の外部で使用するための URL を生成します。
  • 外部サービスに対する絶対リダイレクト URL を生成します。 たとえば、認証が成功した後でユーザーを返す必要がある場所を示すために、Azure Active Directory (Azure AD) などの認証サービスに対して。
  • Cookie の Domain 属性で定義されている、特定のホストに制限される HTTP Cookie を発行します。

アプリケーションの構成に必要なホスト名を追加し、要求で着信ホスト名の代わりに、静的に定義された値を使うことにより、これらの要件をすべて満たすことができます。 ただし、この方法では、アプリケーションの開発とデプロイが複雑になります。 また、アプリケーションの 1 回のインストールで複数のホストに対応できます。 たとえば、1 つの Web アプリを、すべてが独自の固有のホスト名 (tenant1.contoso.comtenant2.contoso.com など) を持つ複数のアプリケーション テナントに使用できます。

また、着信ホスト名が、アプリケーション コードの外部のコンポーネント、またはアプリケーション サーバー上の完全に制御できないミドルウェアによって、使用されることもあります。 次に例をいくつか示します。

  • App Service では、Web アプリに HTTPS を適用することができます。 そのようにすると、セキュリティで保護されていない HTTP 要求が HTTPS にリダイレクトされます。 この場合、着信ホスト名を使用して、HTTP リダイレクトの Location ヘッダーの絶対 URL が生成されます。
  • Spring Apps では、同様の機能を使用して HTTPS が強制されます。 また、着信ホストを使用して HTTPS URL が生成されます。
  • App Service には、同じブラウザー インスタンスからの要求が常に同じバックエンド サーバーによって処理されるように、固定セッションを有効にするための ARR アフィニティ設定があります。 これは App Service フロントエンドによって実行され、HTTP の応答に Cookie が追加されます。 Cookie の Domain には、着信ホストが設定されます。
  • ユーザーが API で簡単にサインインしてデータにアクセスできるようにするため、App Service によって認証と承認の機能が提供されます。

ホスト名を上書きするのが望ましい場合がある理由

たとえば、既定のドメインが contoso.azurewebsites.net である Web アプリケーションを App Service で作成するとします。 (または Spring Apps などの別のサービスの場合。) App Service でカスタム ドメインを構成していません。 このアプリケーションの前面に Application Gateway (または同様のサービス) のようなリバース プロキシを配置するには、Application Gateway の IP アドレスに解決されるように contoso.com の DNS レコードを設定します。 したがって、それはブラウザーから contoso.com に対する要求を受信し、contoso.azurewebsites.net が解決された IP アドレスにその要求を転送するように構成されます。これは、要求されたホストの最終的なバックエンド サービスです。 しかし、この場合、App Service はカスタム ドメイン contoso.com を認識せず、このホスト名に対するすべての着信要求を拒否します。 要求のルーティング先を決定することはできません。

この構成作業を行う簡単な方法は、Application Gateway で HTTP 要求の Host ヘッダーをオーバーライドするか書き換えて、contoso.azurewebsites.net の値に設定することであるように思えるかもしれません。 そのようにした場合、Application Gateway からの発信要求では、元の要求が contoso.com ではなく本当に contoso.azurewebsites.net に対するものであったように見えます。

Diagram that illustrates a configuration with the host name overridden.

この時点で、App Service はホスト名を認識して要求を受け入れます。カスタム ドメイン名を構成する必要はありません。 実際、Application Gateway を使うと、バックエンド プールのホストでホスト ヘッダーをオーバーライドするのが簡単になりますAzure Front Door でも既定でそれが行われます

ただし、この解決策の問題は、アプリで元のホスト名がわからないと、さまざまな問題が発生する可能性があるということです。

潜在的な問題

正しくない絶対 URL

元のホスト名が維持されず、アプリケーション サーバーが着信ホスト名を使って絶対 URL を生成した場合、バックエンド ドメインがエンド ユーザーに公開される可能性があります。 このような絶対 URL は、アプリケーションのコードによって、または前述のように、App Service や Spring Apps での HTTP から HTTPS へのリダイレクトのサポートなどのプラットフォーム機能によって、生成される可能性があります。 次の図は、この問題を示したものです。

Diagram that illustrates the problem of incorrect absolute URLs.

  1. ブラウザーは、contoso.com への要求をリバース プロキシに送信します。
  2. リバース プロキシは、バックエンド Web アプリケーション (または別のサービスの同様の既定のドメイン) への要求で、ホスト名を contoso.azurewebsites.net に書き換えます。
  3. アプリケーションは、着信ホスト名 contoso.azurewebsites.net を基にして絶対 URL を生成します (https://contoso.azurewebsites.net/ など)。
  4. ブラウザーはこの URL に従いますが、それは、contoso.com のリバース プロキシに戻るのではなく、バックエンド サービスに直接移動します。

これにより、リバース プロキシが Web アプリケーション ファイアウォールとしても機能する一般的なケースで、セキュリティ上のリスクが発生する可能性があります。 ユーザーは、バックエンド アプリケーションに直接移動してリバース プロキシをバイパスする URL を受け取ります。

重要

このセキュリティ リスクのため、バックエンド Web アプリケーションではリバース プロキシから直接受け取るネットワーク トラフィックのみを受け入れるようにする必要があります (たとえば、App Service でのアクセス制限を使って)。 そのようにすれば、正しくない絶対 URL が生成された場合でも、少なくともそれは機能せず、悪意のあるユーザーがファイアウォールをバイパスするために使うことはできません。

正しくないリダイレクト URL

前のシナリオの一般的でより具体的なケースは、絶対リダイレクト URL が生成されるときに発生します。 このような URL は、OpenID Connect、OAuth 2.0、SAML 2.0 のようなブラウザー ベースの ID プロトコルを使用する場合に、Azure AD などの ID サービスで必要になります。 これらのリダイレクト URL は、アプリケーション サーバーまたはミドルウェア自体によって、また、前述のように、App Service の認証と承認の機能のようなプラットフォーム機能によって、生成される可能性があります。 次の図は、この問題を示したものです。

Diagram that illustrates the problem of incorrect redirect URLs.

  1. ブラウザーは、contoso.com への要求をリバース プロキシに送信します。
  2. リバース プロキシは、バックエンド Web アプリケーション (または別のサービスの同様の既定のドメイン) への要求で、ホスト名を contoso.azurewebsites.net に書き換えます。
  3. アプリケーションは、着信ホスト名 contoso.azurewebsites.net を基にして絶対リダイレクト URL を生成します (https://contoso.azurewebsites.net/ など)。
  4. ブラウザーは ID プロバイダーにアクセスしてユーザーを認証します。 要求には、認証の成功後にユーザーを返す場所を示すために生成されるリダイレクト URL が含まれます。
  5. 通常、ID プロバイダーではリダイレクト URL が前もって登録されている必要があり、提供されるリダイレクト URL は登録されていないため、この時点で、ID プロバイダーは要求を拒否する必要があります。 (使用は想定されていませんでした。) しかし、何らかの理由でリダイレクト URL が登録されていた場合、ID プロバイダーは認証要求で指定されたリダイレクト URL にブラウザーをリダイレクトします。 この場合、その URL は https://contoso.azurewebsites.net/ になります。
  6. ブラウザーはこの URL に従いますが、それはリバース プロキシに戻るのではなく、バックエンド サービスに直接移動します。

破損した Cookie

アプリケーション サーバーが Cookie を発行し、着信ホスト名を使って Cookie の Domain 属性を作成するときにも、ホスト名の不一致により問題が発生する可能性があります。 Domain 属性を使用すると、その特定のドメインに対してだけ Cookie が使用されます。 このような Cookie は、アプリケーションのコードによって、または前に説明したように、App Service の ARR アフィニティの設定のようなプラットフォーム機能によって生成できます。 次の図は、この問題を示したものです。

Diagram that illustrates an incorrect cookie domain.

  1. ブラウザーは、contoso.com への要求をリバース プロキシに送信します。
  2. リバース プロキシは、バックエンド Web アプリケーション (または別のサービスの同様の既定のドメイン) への要求で、ホスト名を contoso.azurewebsites.net に書き換えます。
  3. アプリケーションは、着信ホスト名 contoso.azurewebsites.net に基づくドメインを使用するクッキーを生成します。 ブラウザーは、ユーザーが実際に使用している contoso.com ドメインではなく、この特定のドメインに対する Cookie を格納します。
  4. Cookie の contoso.azurewebsites.net ドメインが要求のドメインと一致しないので、ブラウザーはそれ以降の contoso.com に対する要求に Cookie を含めません。 アプリケーションは、前に発行した Cookie を受け取りません。 その結果、Cookie に含まれるはずの状態をユーザーが失ったり、ARR アフィニティなどの機能が動作しない可能性があります。 残念ながら、これらの問題はいずれもエラーにはならないか、エンド ユーザーからは直接見えません。 そのため、トラブルシューティングが困難になります。

一般的な Azure サービスの実装ガイダンス

ここで説明する潜在的な問題を回避するには、リバース プロキシとバック エンド アプリケーション サーバーの間で、呼び出しの元のホスト名を維持することをお勧めします。

Diagram that shows a configuration in which the host name is preserved.

バックエンドの構成

多くの Web ホスティング プラットフォームでは、許可される着信ホスト名を明示的に構成する必要があります。 以下のセクションでは、最も一般的な Azure サービスでこの構成を実装する方法について説明します。 通常、他のプラットフォームにもカスタム ドメインを構成するための同様の方法が用意されています。

App Service で Web アプリケーションをホストする場合は、カスタム ドメイン名を Web アプリにアタッチし、バックエンドに対して既定の azurewebsites.net ホスト名を使用しないようにすることができます。 カスタム ドメインを Web アプリにアタッチするときに、DNS の解決を変更する必要はありません。TXT レコードを使ってドメインを検証することができ、通常の CNAME または A レコードに影響はありません。 (これらのレコードは、リバース プロキシの IP アドレスに引き続き解決されます)。エンド ツー エンドの TLS/SSL が必要な場合は、既存の証明書をインポートするか、カスタム ドメインに無料のマネージド証明書を使用できます。

同様に、Spring Apps を使っている場合は、azuremicroservices.io ホスト名を使わずに、アプリのカスタム ドメインを使用することができます。 エンドツーエンドの TLS/SSL が必要な場合は、既存の証明書または自己署名証明書をインポートできます。

API Management (それ自体もリバース プロキシとして機能します) の前面にリバース プロキシがある場合、azure-api.net ホスト名の使用を避けるように、API Management インスタンスでカスタム ドメインを構成することができます。 エンドツーエンドの TLS/SSL が必要な場合は、既存の証明書または無料のマネージド証明書をインポートできます。 ただし、前に説明したように、API はホスト名の不一致によって発生する問題の影響をほとんど受けないので、この構成はそれほど重要ではない可能性があります。

他のプラットフォーム (Kubernetes 上や、直接仮想マシン上など) でアプリケーションをホストする場合、着信ホスト名に依存する組み込みの機能はありません。 アプリケーション サーバー自体でのホスト名の使用方法については、ユーザーが責任を負います。 ホスト名を維持するという推奨事項は、アプリケーションがリバース プロキシを認識するように特に構成され、たとえば forwardedX-Forwarded-Host ヘッダーを尊重しているのでない限り、通常、アプリケーション内のホスト名に依存するすべてのコンポーネントに適用されます。

リバース プロキシの構成

リバース プロキシ内でバックエンドを定義する場合でも、バックエンド サービスの既定のドメインを使用できます (例: https://contoso.azurewebsites.net/)。 この URL は、リバース プロキシによって、バックエンド サービスの正しい IP アドレスを解決するために使われます。 プラットフォームの既定のドメインを使う場合は、IP アドレスが正しいことが常に保証されます。 通常、contoso.com のような公開ドメインは、リバース プロキシ自体の IP アドレスに解決される必要があるため、使用できません。 (水平分割 DNS のようなさらに高度な DNS 解決手法を使用しない場合)。

重要

リバース プロキシと最終的なバックエンドの間に Azure Firewall Premium のような次世代ファイアウォールがある場合は、水平分割 DNS の使用が必要になることがあります。 この種類のファイアウォールでは、HTTP の Host ヘッダーがターゲットの IP アドレスに解決されるかどうかが明示的に調べられる場合があります。 このような場合、ブラウザーによって使用される元のホスト名は、パブリック インターネットからアクセスされるときは、リバース プロキシの IP アドレスに解決される必要があります。 ただし、ファイアウォールの観点からは、そのホスト名は最終的なバックエンド サービスの IP アドレスに解決される必要があります。 詳しくは、「Azure Firewall と Application Gateway を使用した Web アプリケーション用のゼロ トラスト ネットワーク」をご覧ください。

ほとんどのリバース プロキシでは、バックエンド サービスに渡されるホスト名を構成できます。 次の情報では、最も一般的な Azure サービスについて、着信要求の元のホスト名が使われるようにする方法について説明します。

注意

すべての場合で、受信要求からホスト名を取得するのではなく、明示的に定義されたカスタム ドメインでホスト名をオーバーライドすることができます。 アプリケーションで使われているドメインが 1 つだけの場合、その方法は問題なく動作する可能性があります。 同じアプリケーションのデプロイが複数のドメインからの要求を受け入れる場合は (マルチテナント シナリオなど)、1 つのドメインを静的に定義できません。 着信要求からホスト名を取得する必要があります (やはり、追加の HTTP ヘッダーを考慮するようにアプリケーションが明示的にコーディングされていない限り)。 そのため、一般的には、ホスト名をまったくオーバーライドしないことをお勧めします。 着信ホスト名を変更しないでバックエンドに渡します。

Application Gateway

リバース プロキシとして Application Gateway を使う場合は、バックエンド HTTP の設定で [新しいホスト名でオーバーライドする] を無効にすることで、元のホスト名が維持されるようにできます。 これにより、バックエンド アドレスからのホスト名の取得特定のドメイン名でのオーバーライドの両方が無効になります。 (どちらの設定もホスト名に優先します。) Application Gateway 用の Azure Resource Manager のプロパティでは、この構成は hostName プロパティを null に設定し、pickHostNameFromBackendAddress プロパティを false に設定することに相当します。

正常性プローブは着信要求のコンテキストの外部で送信されるので、正しいホスト名を動的に特定できません。 代わりに、カスタム正常性プローブを作成し、バックエンドの HTTP 設定からのホスト名の取得ホスト名の明示的な指定を無効にする必要があります。 このホスト名では、整合性のために、適切なカスタム ドメインを使用する必要もあります。 (ただし、正常性プローブでは応答に含まれる正しくない Cookie またはリダイレクト URL は無視されるので、ここではホスティング プラットフォームの既定のドメインを使用できます)。

Azure Front Door

Azure Front Door を使用する場合は、バックエンド プールの定義でバックエンド ホスト ヘッダーを空白のままにすることで、ホスト名のオーバーライドを回避できます。 バックエンド プールの Resource Manager の定義では、この構成は backendHostHeadernull に設定することに対応します。

Azure Front Door Standard または Premium を使う場合は、配信元の定義で配信元のホスト ヘッダーを空白のままにすることで、ホスト名を維持できます。 配信元の Resource Manager の定義では、この構成は originHostHeadernull に設定することに対応します。

API Management

既定では、API Management は、バックエンドに送信されるホスト名を、API の Web サービス URL (API の Resource Manager 定義serviceUrl の値に対応します) のホスト コンポーネントでオーバーライドします。

次のように、inboundHTTP ヘッダー設定ポリシー追加することで、着信要求のホスト名を代わりに使うことを、API Management に強制できます。

<inbound>
  <base />
  <set-header name="Host" exists-action="override">
    <value>@(context.Request.OriginalUrl.Host)</value>
  </set-header>
</inbound>

ただし、前に説明したように、API はホスト名の不一致によって発生する問題の影響をほとんど受けないので、この構成はそれほど重要ではない可能性があります。

次のステップ