Web アプリケーションの前面でリバース プロキシを使うときは、元の HTTP ホスト名を維持することをお勧めします。 バックエンド アプリケーション サーバーに提供されるものとは異なるホスト名をリバース プロキシで使うと、Cookie やリダイレクト URL が正しく機能しない可能性があります。 たとえば、セッション状態が失われたり、認証が失敗したり、バックエンド URL が誤ってエンド ユーザーに公開されたりすることがあります。 アプリケーション サーバーが Web ブラウザーと同じドメインを認識するように、初期要求のホスト名を保持することで、これらの問題を回避できます。
このガイダンスは、Azure App Service や Azure Spring Apps など、サービスとしてのプラットフォーム (PaaS) オファリングでホストされるアプリケーションに特に当てはまります。 この記事では、よく使われるリバース プロキシ サービスである Azure Application Gateway、Azure Front Door、Azure API Management に関する具体的な実装ガイダンスを提供します。
注意
Web API は、一般に、ホスト名の不一致によって発生する問題に対する影響をそれほど受けません。 シングルページ アプリとそのバックエンド API の間の通信をセキュリティ保護するために Cookie を使用する (たとえば、フロントエンド用バックエンドと呼ばれるパターン) 場合を除き、通常は Cookie に依存しません。 Open Data Protocol (OData) や HATEOAS のような特定の API スタイルを除き、多くの場合、Web API は絶対 URL をそれ自体に返しません。 API の実装が Cookie に依存している場合、または絶対 URL を生成する場合は、この記事で説明されているガイダンスが適用されます。
エンドツーエンドの TLS/SSL が必要な場合は (リバース プロキシとバックエンド サービスの間の接続で HTTPS が使用されている)、バックエンド サービスで元のホスト名に対応する TLS 証明書も必要になります。 この要件により、証明書を展開および更新するときの運用の複雑さが増しますが、多くの PaaS サービスでは、フル マネージドの無料の TLS 証明書が提供されています。
Context
HTTP 要求のホスト
多くの場合、アプリケーション サーバーまたは要求パイプライン内の一部のコンポーネントでは、ブラウザーがそれにアクセスするために使ったインターネット ドメイン名が必要になります。 これは、要求の "ホスト" です。 それは IP アドレスのこともありますが、通常は、contoso.com
のような名前です (その場合、ブラウザーにより DNS を使って IP アドレスに解決されます)。 通常、ホストの値は要求 URI のホスト コンポーネントによって決定されます。これは、ブラウザーが Host
HTTP ヘッダーとしてアプリケーションに送信します。
重要
セキュリティ メカニズムでホストの値を使用しないでください。 この値は、ブラウザーまたは他のユーザー エージェントによって提供され、エンド ユーザーが簡単に操作できます。
状況によっては (特に、要求チェーン内に HTTP リバース プロキシがある場合)、アプリケーション サーバーに到達する前に元のホスト ヘッダーが変更されることがあります。 リバース プロキシによってクライアント ネットワーク セッションが閉じられ、バックエンドへの新しい接続が設定されます。 この新しいセッションでは、クライアント セッションの元のホスト名を引き継ぐか、新しいものを設定することができます。 後者の場合でも、プロキシは、Forwarded
や X-Forwarded-Host
のような他の HTTP ヘッダーで、元のホストの値を送信することがよくあります。 この値により、アプリケーションで元のホスト名を特定できますが、これらのヘッダーを読み取るようにコーディングされている場合に限られます。
Web プラットフォームでホスト名が使われる理由
マルチテナントの PaaS サービスでは、着信要求を適切なテナントのバックエンド サーバーにルーティングするために、登録および検証されたホスト名が必要になることがよくあります。 これは、通常、すべてのテナントに対する着信要求を受け入れるロード バランサーの共有プールがあるためです。 テナントでは、通常、着信ホスト名を使って、顧客テナントの正しいバックエンドが検索されます。
簡単に使い始めることができるように、これらのプラットフォームでは、通常、デプロイされたインスタンスにトラフィックをルーティングするように事前に構成された既定のドメインが提供されています。 App Service の場合、この既定のドメインは azurewebsites.net
です。 ユーザーが作成した各 Web アプリは、独自のサブドメインを取得します (例: contoso.azurewebsites.net
)。 同様に、既定のドメインは Azure Spring Apps の場合は azuremicroservices.io
で、API Management の場合は azure-api.net
です。
運用環境のデプロイでは、これらの既定のドメインは使用しません。 代わりに、組織またはアプリケーションのブランドに合わせて独自のドメインを提供します。 たとえば、contoso.com
は App Service の contoso.azurewebsites.net
Web アプリにバックグラウンドで解決できますが、Web サイトにアクセスするエンド ユーザーにこのドメインが見えてはなりません。 ただし、この contoso.com
というカスタム ホスト名は PaaS サービスに登録する必要があるため、プラットフォームは要求に応答する必要があるバックエンド サーバーを識別できます。
アプリケーションがホスト名を使用する理由
アプリケーション サーバーでホスト名が必要になる一般的な 2 つの理由は、絶対 URL を作成するためと、特定のドメインの Cookie を発行するためです。 たとえば、アプリケーションのコードで次のことを行う必要がある場合です。
- 相対 URL ではなく絶対 URL を HTTP 応答で返します (ただし、一般に、Web サイトは可能な場合は相対リンクをレンダリングする傾向があります)。
- Web サイトへのリンクをユーザーにメールで送信する場合のように、相対 URL を使用できない HTTP 応答の外部で使用するための URL を生成します。
- 外部サービスに対する絶対リダイレクト URL を生成します。 たとえば、認証が成功した後でユーザーを返すべき場所を示すために、Microsoft Entra ID などの認証サービスに対して。
- Cookie の
Domain
属性で定義されている、特定のホストに制限される HTTP Cookie を発行します。
アプリケーションの構成に必要なホスト名を追加し、要求で着信ホスト名の代わりに、静的に定義された値を使うことにより、これらの要件をすべて満たすことができます。 ただし、この方法では、アプリケーションの開発とデプロイが複雑になります。 また、アプリケーションの 1 回のインストールで複数のホストに対応できます。 たとえば、1 つの Web アプリを、すべてが独自の固有のホスト名 (tenant1.contoso.com
や tenant2.contoso.com
など) を持つ複数のアプリケーション テナントに使用できます。
また、着信ホスト名が、アプリケーション コードの外部のコンポーネント、またはアプリケーション サーバー上の完全に制御できないミドルウェアによって、使用されることもあります。 次に例をいくつか示します。
- App Service では、Web アプリに HTTPS を適用することができます。 そのようにすると、セキュリティで保護されていない HTTP 要求が HTTPS にリダイレクトされます。 この場合、着信ホスト名を使用して、HTTP リダイレクトの
Location
ヘッダーの絶対 URL が生成されます。 - Azure Spring Apps では、同様の機能を使用して HTTPS が強制されます。 また、着信ホストを使用して HTTPS URL が生成されます。
- App Service には、同じブラウザー インスタンスからの要求が常に同じバックエンド サーバーによって処理されるように、固定セッションを有効にするための ARR アフィニティ設定があります。 これは App Service フロントエンドによって実行され、HTTP の応答に Cookie が追加されます。 Cookie の
Domain
には、着信ホストが設定されます。 - ユーザーが API で簡単にサインインしてデータにアクセスできるようにするため、App Service によって認証と承認の機能が提供されます。
- 着信ホスト名を使って、認証が成功した後に ID プロバイダーがユーザーを返す必要があるリダイレクト URL が作成されます。
- この機能を有効にすると、既定で HTTP から HTTPS へのリダイレクトも有効になります。 やはり、着信ホスト名を使ってリダイレクトの場所が生成されます。
ホスト名を上書きするのが望ましい場合がある理由
たとえば、既定のドメインが contoso.azurewebsites.net
である Web アプリケーションを App Service で作成するとします。 (または Azure 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
に対するものであったように見えます。
この時点で、App Service はホスト名を認識して要求を受け入れます。カスタム ドメイン名を構成する必要はありません。 実際、Application Gateway を使うと、バックエンド プールのホストでホスト ヘッダーをオーバーライドするのが簡単になります。 Azure Front Door でも既定でそれが行われます。
ただし、この解決策の問題は、アプリで元のホスト名がわからないと、さまざまな問題が発生する可能性があるということです。
潜在的な問題
正しくない絶対 URL
元のホスト名が維持されず、アプリケーション サーバーが着信ホスト名を使って絶対 URL を生成した場合、バックエンド ドメインがエンド ユーザーに公開される可能性があります。 このような絶対 URL は、アプリケーションのコードによって、または前述のように、App Service や Azure Spring Apps での HTTP から HTTPS へのリダイレクトのサポートなどのプラットフォーム機能によって、生成される可能性があります。 次の図は、この問題を示したものです。
- ブラウザーは、
contoso.com
への要求をリバース プロキシに送信します。 - リバース プロキシは、バックエンド Web アプリケーション (または別のサービスの同様の既定のドメイン) への要求で、ホスト名を
contoso.azurewebsites.net
に書き換えます。 - アプリケーションは、着信ホスト名
contoso.azurewebsites.net
を基にして絶対 URL を生成します (https://contoso.azurewebsites.net/
など)。 - ブラウザーはこの URL に従いますが、それは、
contoso.com
のリバース プロキシに戻るのではなく、バックエンド サービスに直接移動します。
これにより、リバース プロキシが Web アプリケーション ファイアウォールとしても機能する一般的なケースで、セキュリティ上のリスクが発生する可能性があります。 ユーザーは、バックエンド アプリケーションに直接移動してリバース プロキシをバイパスする URL を受け取ります。
重要
このセキュリティ リスクのため、バックエンド Web アプリケーションではリバース プロキシから直接受け取るネットワーク トラフィックのみを受け入れるようにする必要があります (たとえば、App Service でのアクセス制限を使って)。 そのようにすれば、正しくない絶対 URL が生成された場合でも、少なくともそれは機能せず、悪意のあるユーザーがファイアウォールをバイパスするために使うことはできません。
正しくないリダイレクト URL
前のシナリオの一般的でより具体的なケースは、絶対リダイレクト URL が生成されるときに発生します。 これらの URL は、OpenID Connect、Open Authorization (OAuth) 2.0、Security Assertion Markup Language (SAML) 2.0 などのブラウザーベースの ID プロトコルを使用する場合に、Microsoft Entra IDなどの ID サービスで必要です。 これらのリダイレクト URL は、アプリケーション サーバーまたはミドルウェア自体によって、あるいは前述のように、App Service の認証と承認の機能などのプラットフォーム機能によって、生成される可能性があります。 次の図は、この問題を示したものです。
- ブラウザーは、
contoso.com
への要求をリバース プロキシに送信します。 - リバース プロキシは、バックエンド Web アプリケーション (または別のサービスの同様の既定のドメイン) への要求で、ホスト名を
contoso.azurewebsites.net
に書き換えます。 - アプリケーションは、着信ホスト名
contoso.azurewebsites.net
を基にして絶対リダイレクト URL を生成します (https://contoso.azurewebsites.net/
など)。 - ブラウザーは ID プロバイダーにアクセスしてユーザーを認証します。 要求には、認証の成功後にユーザーを返す場所を示すために生成されるリダイレクト URL が含まれます。
- 通常、ID プロバイダーではリダイレクト URL が前もって登録されている必要があり、提供されるリダイレクト URL は登録されていないため、この時点で、ID プロバイダーは要求を拒否する必要があります。 (使用は想定されていませんでした。) しかし、何らかの理由でリダイレクト URL が登録されていた場合、ID プロバイダーは認証要求で指定されたリダイレクト URL にブラウザーをリダイレクトします。 この場合、その URL は
https://contoso.azurewebsites.net/
になります。 - ブラウザーはこの URL に従いますが、それはリバース プロキシに戻るのではなく、バックエンド サービスに直接移動します。
破損した Cookie
アプリケーション サーバーが Cookie を発行し、着信ホスト名を使って Cookie の Domain
属性を作成するときにも、ホスト名の不一致により問題が発生する可能性があります。 Domain 属性を使用すると、その特定のドメインに対してだけ Cookie が使用されます。 このような Cookie は、アプリケーションのコードによって、または前述のように、App Service の ARR アフィニティの設定などのプラットフォーム機能によって、生成される可能性があります。 次の図は、この問題を示したものです。
- ブラウザーは、
contoso.com
への要求をリバース プロキシに送信します。 - リバース プロキシは、バックエンド Web アプリケーション (または別のサービスの同様の既定のドメイン) への要求で、ホスト名を
contoso.azurewebsites.net
に書き換えます。 - アプリケーションは、着信ホスト名
contoso.azurewebsites.net
に基づくドメインを使用するクッキーを生成します。 ブラウザーは、ユーザーが実際に使用しているcontoso.com
ドメインではなく、この特定のドメインに対する Cookie を格納します。 - Cookie の
contoso.azurewebsites.net
ドメインが要求のドメインと一致しないので、ブラウザーはそれ以降のcontoso.com
に対する要求に Cookie を含めません。 アプリケーションは、前に発行した Cookie を受け取りません。 その結果、Cookie に含まれるはずの状態をユーザーが失ったり、ARR アフィニティなどの機能が動作しない可能性があります。 残念ながら、これらの問題はいずれもエラーにはならないか、エンド ユーザーからは直接見えません。 そのため、トラブルシューティングが困難になります。
一般的な Azure サービスの実装ガイダンス
ここで説明する潜在的な問題を回避するには、リバース プロキシとバック エンド アプリケーション サーバーの間で、呼び出しの元のホスト名を維持することをお勧めします。
バックエンドの構成
多くの Web ホスティング プラットフォームでは、許可される着信ホスト名を明示的に構成する必要があります。 以下のセクションでは、最も一般的な Azure サービスでこの構成を実装する方法について説明します。 通常、他のプラットフォームにもカスタム ドメインを構成するための同様の方法が用意されています。
App Service で Web アプリケーションをホストする場合は、カスタム ドメイン名を Web アプリにアタッチし、バックエンドに対して既定の azurewebsites.net
ホスト名を使用しないようにすることができます。 カスタム ドメインを Web アプリにアタッチするときに、DNS の解決を変更する必要はありません。TXT
レコードを使ってドメインを検証することができ、通常の CNAME
または A
レコードに影響はありません。 (これらのレコードは、引き続きリバース プロキシの IP アドレスに解決されます)。エンド ツー エンドの TLS/SSL が必要な場合は、Key Vault から既存の証明書をインポートすることも、カスタム ドメインの App Service 証明書を使用することもできます。 (この場合、無料の App Service マネージド証明書は使用できません。これは、ドメインの DNS レコードがリバース プロキシではなく、App Service に直接解決される必要があるためです)。
同様に、Spring Apps を使っている場合は、azuremicroservices.io
ホスト名を使わずに、アプリのカスタム ドメインを使用することができます。 エンドツーエンドの TLS/SSL が必要な場合は、既存の証明書または自己署名証明書をインポートできます。
API Management (それ自体もリバース プロキシとして機能します) の前面にリバース プロキシがある場合、azure-api.net
ホスト名の使用を避けるように、API Management インスタンスでカスタム ドメインを構成することができます。 エンドツーエンドの TLS/SSL が必要な場合は、既存の証明書または無料のマネージド証明書をインポートできます。 ただし、前に説明したように、API はホスト名の不一致によって発生する問題の影響をほとんど受けないので、この構成はそれほど重要ではない可能性があります。
他のプラットフォーム (Kubernetes 上や、直接仮想マシン上など) でアプリケーションをホストする場合、着信ホスト名に依存する組み込みの機能はありません。 アプリケーション サーバー自体でのホスト名の使用方法については、ユーザーが責任を負います。 ホスト名を維持するという推奨事項は、アプリケーションがリバース プロキシを認識するように特に構成され、たとえば forwarded
や X-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 の定義では、この構成は backendHostHeader
を null
に設定することに対応します。
Azure Front Door Standard または Premium を使う場合は、配信元の定義で配信元のホスト ヘッダーを空白のままにすることで、ホスト名を維持できます。 配信元の Resource Manager の定義では、この構成は originHostHeader
を null
に設定することに対応します。
API Management
既定では、API Management は、バックエンドに送信されるホスト名を、API の Web サービス URL (API の Resource Manager 定義の serviceUrl
の値に対応します) のホスト コンポーネントでオーバーライドします。
次のように、inbound
HTTP ヘッダー設定ポリシー追加することで、着信要求のホスト名を代わりに使うことを、API Management に強制できます。
<inbound>
<base />
<set-header name="Host" exists-action="override">
<value>@(context.Request.OriginalUrl.Host)</value>
</set-header>
</inbound>
ただし、前に説明したように、API はホスト名の不一致によって発生する問題の影響をほとんど受けないので、この構成はそれほど重要ではない可能性があります。