保留反向 Proxy 與其後端 Web 應用程式之間的原始 HTTP 主機名稱

Azure API 管理
Azure App Service
Azure 應用程式閘道
Azure Front Door
Azure Spring Apps

當您在 Web 應用程式前面使用反向 Proxy 時,建議您保留原始的 HTTP 主機名稱。 在反向 Proxy 上擁有不同于提供給後端應用程式伺服器的主機名稱,可能會導致 Cookie 或重新導向 URL 無法正常運作。 例如,會話狀態可能會遺失、驗證可能會失敗,或後端 URL 不小心會公開給終端使用者。 您可以保留初始要求的主機名稱來避免這些問題,讓應用程式伺服器看到與網頁瀏覽器相同的網域。

本指南特別適用于裝載于平臺即服務 (PaaS) 供應專案的應用程式,例如 Azure App 服務 Azure Spring Apps 。 本文提供Azure 應用程式閘道 Azure Front Door Azure API 管理 的特定 實作指引 ,這些服務是常用的反向 Proxy 服務。

注意

Web API 通常較不區分主機名稱不符所造成的問題。 除非您 使用 Cookie 來保護單頁應用程式與其後端 API 之間的通訊,例如,在稱為 前端 後端的模式中,它們通常不會相依于 Cookie。 Web API 通常不會將絕對 URL 傳回給自己,但某些 API 樣式除外,例如 OData HATEOAS 。 如果您的 API 實作相依于 Cookie 或產生絕對 URL,則本文中提供的指引會適用。

如果您需要端對端 TLS/SSL(反向 Proxy 與後端服務之間的連線使用 HTTPS),後端服務也需要原始主機名稱的相符 TLS 憑證。 當您部署和更新憑證時,這項需求會增加作業複雜性,但許多 PaaS 服務都會提供完全受控的免費 TLS 憑證。

上下文

HTTP 要求的主機

在許多情況下,應用程式伺服器或要求管線中的某些元件需要瀏覽器用來存取它的網際網路功能變數名稱。 這是 要求的主機 。 它可以是 IP 位址,但通常是類似 contoso.com 的名稱(瀏覽器接著會使用 DNS 解析為 IP 位址)。 主機值通常是從要求 URI 的主機元件決定,瀏覽器會以 HTTP 標頭 的形式傳送至應用程式 Host

重要

請勿在安全性機制中使用主機的值。 此值是由瀏覽器或其他一些使用者代理程式提供,而且可由使用者輕鬆操作。

在某些情況下,特別是在要求鏈結中有 HTTP 反向 Proxy 時,原始主機標頭可以在到達應用程式伺服器之前變更。 反向 Proxy 會關閉用戶端網路會話,並設定與後端的新連線。 在這個新的會話中,它可以延續用戶端會話的原始主機名稱,或設定新的主機名稱。 在後者的情況下,Proxy 通常會在其他 HTTP 標頭中傳送原始主機值,例如 ForwardedX-Forwarded-Host 。 這個值可讓應用程式判斷原始主機名稱,但前提是它們已編碼為讀取這些標頭。

為何 Web 平臺使用主機名稱

多租使用者 PaaS 服務通常需要已註冊和驗證的主機名稱,才能將連入要求路由傳送至適當的租使用者的後端伺服器。 這是因為通常會有一個共用的負載平衡器集區,可接受所有租使用者的連入要求。 租使用者通常會使用傳入的主機名稱來查閱客戶租使用者的正確後端。

為了方便開始使用,這些平臺通常會提供預先設定的預設網域,以將流量路由傳送至已部署的實例。 針對 App Service,此預設網域為 azurewebsites.net 。 您建立的每個 Web 應用程式都會取得自己的子域,例如 contoso.azurewebsites.net 。 同樣地,預設網域適用于 azuremicroservices.io Spring Apps 和 azure-api.net API 管理。

針對生產環境部署,您不會使用這些預設網域。 相反地,您可以提供自己的網域,以配合您的組織或應用程式的品牌。 例如, contoso.com 可以在 App Service 上將幕後解析為 contoso.azurewebsites.net Web 應用程式,但流覽網站的終端使用者不應該看到此網域。 不過,此自訂 contoso.com 主機名稱必須向 PaaS 服務註冊,因此平臺可以識別應該回應要求的後端伺服器。

Diagram that illustrates host-based routing in App Service.

應用程式為何使用主機名稱

應用程式伺服器需要主機名稱的兩個常見原因是建構絕對 URL,並針對特定網域發出 Cookie。 例如,當應用程式程式碼需要:

  • 傳回其 HTTP 回應中的絕對而非相對 URL(雖然網站通常會盡可能轉譯相對連結)。
  • 產生 URL,以在其 HTTP 回應外部使用,其中無法使用相對 URL,例如將網站連結傳送給使用者的電子郵件。
  • 產生外部服務的絕對重新導向 URL。 例如,在 Microsoft Entra ID 之類的驗證服務中,表示成功驗證後應該傳回使用者的位置。
  • 發出限制為特定主機的 HTTP Cookie,如 Cookie 的 Domain 屬性 中所定義。

您可以將預期的主機名稱新增至應用程式的組態,並使用靜態定義的值,而不是要求上的傳入主機名稱,以符合所有這些需求。 不過,這種方法會使應用程式開發和部署複雜化。 此外,應用程式的單一安裝也可以為多部主機提供服務。 例如,單一 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 前端所執行,其會將 Cookie 新增至 HTTP 回應。 Cookie 的 Domain 會設定為傳入主機。
  • App Service 提供 驗證和授權功能 ,讓使用者輕鬆登入和存取 API 中的資料。

為何您可能想要覆寫主機名稱

假設您在 App Service 中建立具有預設網域的 contoso.azurewebsites.net Web 應用程式。 (或在另一個服務,如 Spring Apps。您尚未在 App Service 上設定自訂網域。 若要在此應用程式前面放置像是 應用程式閘道(或任何類似服務)的反向 Proxy,請將 的 DNS 記錄 contoso.com 設定為 解析為 應用程式閘道 的 IP 位址。 因此,它會從瀏覽器接收 要求 contoso.com ,並設定為將該要求轉送至解析為的 IP 位址 contoso.azurewebsites.net :這是所要求主機的最終後端服務。 不過,在此情況下,App Service 無法辨識 contoso.com 自訂網域,並拒絕此主機名稱的所有連入要求。 它無法判斷路由要求的位置。

讓此組態運作的簡單方式似乎是在 應用程式閘道 中覆寫或重寫 Host HTTP 要求的標頭,並將其設定為 的值 contoso.azurewebsites.net 。 如果您這麼做,來自 應用程式閘道 的傳出要求會讓原始要求看起來確實適用于 contoso.azurewebsites.net ,而不是 contoso.com

Diagram that illustrates a configuration with the host name overridden.

此時,App Service 會辨識主機名稱,而且它會接受要求,而不需要設定自訂功能變數名稱。 事實上, 應用程式閘道可讓您輕鬆地使用後端集區的主機覆寫主機標頭 Azure Front Door 預設 也會這麼做。

不過,此解決方案的問題在於,當應用程式看不到原始主機名稱時,可能會導致各種問題。

潛在問題

不正確的絕對 URL

如果未保留原始主機名稱,而且應用程式伺服器會使用連入主機名稱來產生絕對 URL,則後端網域可能會向終端使用者透露。 這些絕對 URL 可由應用程式程式碼產生,或如先前所述,由 App Service 和 Spring Apps 中支援 HTTP 對 HTTPS 重新導向等平臺功能所產生。 下圖說明問題:

Diagram that illustrates the problem of incorrect absolute URLs.

  1. 瀏覽器會將 的要求 contoso.com 傳送至反向 Proxy。
  2. 反向 Proxy 會將要求中的主機名稱重寫為 contoso.azurewebsites.net 後端 Web 應用程式 (或另一個服務的類似預設網域)。
  3. 應用程式會產生以傳入 contoso.azurewebsites.net 主機名稱為基礎的絕對 URL, https://contoso.azurewebsites.net/ 例如 。
  4. 瀏覽器會遵循此 URL,直接前往後端服務,而不是回到 位於 contoso.com 的反向 Proxy。

在反向 Proxy 也做為 Web 應用程式防火牆的常見案例中,這甚至可能會造成安全性風險。 使用者會收到直接前往後端應用程式的 URL,並略過反向 Proxy。

重要

由於此安全性風險,您必須確保後端 Web 應用程式只直接接受來自反向 Proxy 的網路流量(例如,在 App Service 中使用 存取限制)。 如果您這樣做,即使產生不正確的絕對 URL,至少它無法運作,也無法由惡意使用者用來略過防火牆。

不正確的重新導向 URL

產生絕對重新導向 URL 時,會發生先前案例的常見且更具體的情況。 當您使用 OpenID 連線、OAuth 2.0 或 SAML 2.0 等瀏覽器型身分識別通訊協定時,Microsoft Entra ID 等身分識別服務需要這些 URL。 這些重新導向 URL 可由應用程式伺服器或中介軟體本身產生,或如先前所述,由 App Service 驗證和授權功能等平臺功能 所指出。 下圖說明問題:

Diagram that illustrates the problem of incorrect redirect URLs.

  1. 瀏覽器會將 的要求 contoso.com 傳送至反向 Proxy。
  2. 反向 Proxy 會將要求上的主機名稱重寫為 contoso.azurewebsites.net 後端 Web 應用程式(或另一個服務的類似預設網域)。
  3. 應用程式會產生以傳入 contoso.azurewebsites.net 主機名稱為基礎的絕對重新導向 URL,例如 https://contoso.azurewebsites.net/
  4. 瀏覽器會前往識別提供者來驗證使用者。 要求包含產生的重新導向 URL,以指出成功驗證後要傳回使用者的位置。
  5. 識別提供者通常需要預先註冊重新導向 URL,因此此時識別提供者應該拒絕要求,因為未註冊提供的重新導向 URL。 (不應該使用它。不過,如果基於某些原因,重新導向 URL 會註冊,識別提供者會將瀏覽器重新導向至驗證要求中指定的重新導向 URL。 在此情況下,URL 為 https://contoso.azurewebsites.net/
  6. 瀏覽器會遵循此 URL,直接前往後端服務,而不是回到反向 Proxy。

中斷的 Cookie

當應用程式伺服器發出 Cookie 並使用傳入主機名稱來建構 Domain Cookie 屬性時,主機名稱不符也可能會導致問題。 Domain 屬性可確保 Cookie 只會用於該特定網域。 這些 Cookie 可由應用程式程式碼產生,或如先前所述,由 App Service ARR 親和性設定 等平臺功能產生。 下圖說明問題:

Diagram that illustrates an incorrect cookie domain.

  1. 瀏覽器會將 的要求 contoso.com 傳送至反向 Proxy。
  2. 反向 Proxy 會重寫要求中的主機名稱 contoso.azurewebsites.net 給後端 Web 應用程式(或另一個服務的類似預設網域)。
  3. 應用程式會根據傳入 contoso.azurewebsites.net 主機名稱產生使用網域的 Cookie。 瀏覽器會儲存此特定網域的 Cookie,而不是 contoso.com 使用者實際使用的網域。
  4. 瀏覽器不會在任何後續要求 contoso.com 中包含 Cookie,因為 Cookie 的 contoso.azurewebsites.net 網域不符合要求的網域。 應用程式不會收到稍早發出的 Cookie。 因此,使用者可能會遺失應該位於 Cookie 中的狀態,或 ARR 親和性之類的功能無法運作。 不幸的是,這些問題都不會產生錯誤,或使用者無法直接看到。 這使得他們難以進行疑難排解。

常見 Azure 服務的實作指引

若要避免此處討論的潛在問題,建議您在反向 Proxy 與後端應用程式伺服器之間的呼叫中保留原始主機名稱:

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

後端組態

許多 Web 裝載平臺都要求您明確設定允許的傳入主機名稱。 下列各節說明如何針對最常見的 Azure 服務實作此設定。 其他平臺通常會提供類似的方法來設定自訂網域。

如果您在 App Service 中 裝載 Web 應用程式,您可以將 自訂功能變數名稱附加至 Web 應用程式 ,並避免在後端使用預設 azurewebsites.net 主機名稱。 當您將自訂網域附加至 Web 應用程式時,不需要變更 DNS 解析:您可以使用 記錄 來驗證網域 TXT ,而不會影響您的一般 CNAMEA 記錄。 (這些記錄仍會解析為反向 Proxy 的 IP 位址。如果您需要端對端 TLS/SSL,您可以從 金鑰保存庫 匯入現有的憑證,或使用 App Service 憑證 作為自訂網域。 (請注意,免費 在此情況下,無法使用 App Service 受控憑證 ,因為它需要網域的 DNS 記錄直接解析為 App Service,而不是反向 Proxy。

同樣地,如果您使用 Spring Apps ,您可以使用 應用程式的 自訂網域來避免使用 azuremicroservices.io 主機名稱。 如果您需要端對端 TLS/SSL,您可以匯入現有的或自我簽署憑證。

如果您在API 管理前面 有反向 Proxy(這本身也會做為反向 Proxy),您可以在 API 管理實例 上設定自訂網域,以避免使用 azure-api.net 主機名稱。 如果您需要端對端 TLS/SSL,您可以匯入現有的或免費的受控憑證。 不過,如先前所述,API 對主機名稱不符所造成的問題較不敏感,因此此組態可能不如重要。

如果您在其他平臺上 裝載應用程式 ,例如 Kubernetes 或直接裝載在虛擬機器上,則沒有任何內建功能相依于傳入主機名稱。 您必須負責應用程式伺服器本身的主機名稱使用方式。 保留主機名稱的建議通常仍然適用于您應用程式中相依于它的任何元件,除非您特別讓應用程式知道反向 Proxy 並遵守 forwardedX-Forwarded-Host 標頭,例如。

反向 Proxy 設定

當您在反向 Proxy 中定義後端時,您仍然可以使用後端服務的預設網域,例如 https://contoso.azurewebsites.net/ 。 反向 Proxy 會使用此 URL 來解析後端服務的正確 IP 位址。 如果您使用平臺的預設網域,一律會保證 IP 位址正確無誤。 您通常無法使用公開的網域,例如 contoso.com ,因為它應該解析為反向 Proxy 本身的 IP 位址。 (除非您使用更進階的 DNS 解析技術,例如 分割範圍 DNS )。

重要

如果您有新一代防火牆,例如 反向 Proxy 與最終後端之間的Azure 防火牆 進階版 ,您可能需要使用分割地平線 DNS。 這種類型的防火牆可能會明確檢查 HTTP Host 標頭是否解析為目標 IP 位址。 在這些情況下,瀏覽器所使用的原始主機名稱應該會在從公用網際網路存取時解析為反向 Proxy 的 IP 位址。 不過,從防火牆的觀點來看,主機名稱應該解析為最終後端服務的 IP 位址。 如需詳細資訊,請參閱 使用 Azure 防火牆 和 應用程式閘道 的 Web 應用程式零信任網路。

大部分的反向 Proxy 可讓您設定哪一個主機名稱會傳遞至後端服務。 下列資訊說明如何確保針對最常見的 Azure 服務,使用傳入要求的原始主機名稱。

注意

在所有情況下,您也可以選擇使用明確定義的自訂網域來覆寫主機名稱,而不是從傳入要求中擷取它。 如果應用程式只使用單一網域,該方法可能會正常運作。 如果相同的應用程式部署接受來自多個網域的要求(例如在多租使用者案例中),則您無法以靜態方式定義單一網域。 您應該從傳入要求中取得主機名稱(同樣地,除非應用程式已明確編碼以考慮其他 HTTP 標頭)。 因此,一般建議是您根本不應該覆寫主機名稱。 將未修改的傳入主機名稱傳遞至後端。

應用程式閘道

如果您使用 應用程式閘道 做為反向 Proxy,您可以藉由停用後端 HTTP 設定上的 [以新主機名稱覆 寫] 來保留原始主機名稱 。 這樣做會 停用從後端位址 挑選主機名稱和 以特定功能變數名稱 覆寫。 (這兩個設定都會覆寫主機名稱。在 應用程式閘道 Azure Resource Manager 屬性中,此組態會對應至 將 屬性設定 hostNamenullfalsepickHostNameFromBackendAddress

由於健康情況探查是在傳入要求的內容之外傳送,所以無法動態判斷正確的主機名稱。 相反地,您必須建立自訂健康情況探查、從後端 HTTP 設定停用 挑選主機名稱,並 明確指定主機名稱 針對此主機名稱,您也應該使用適當的自訂網域來保持一致性。 不過,您可以在這裡使用主控平臺的預設網域,因為健康情況探查會忽略回應中不正確的 Cookie 或重新導向 URL。

Azure Front Door

如果您使用 Azure Front Door ,您可以在後端集區定義中保留 後端主機標頭 空白,以避免覆寫主機名稱。 在 後端集 區的 Resource Manager 定義中,此組態會對應至 設定 backendHostHeadernull

如果您使用 Azure Front Door Standard 或 進階版 ,您可以在原始定義中保留原始主機標頭 空白來 保留主機名稱。 在 來源 的 Resource Manager 定義中,此組態會對應至 null 的 設定 originHostHeader

API 管理

根據預設, API 管理 會使用 API Web 服務 URL 的主機元件來覆寫傳送至後端的主機名稱(對應至 serviceUrl API 的 Resource Manager 定義值 )。

您可以藉由新增 inbound 設定 HTTP 標頭 原則,強制API 管理改用傳入要求的主機名稱,如下所示:

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

不過,如先前所述,API 對主機名稱不符所造成的問題較不敏感,因此此組態可能不如重要。

下一步