編輯

共用方式為


保留反向 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 ServiceAzure Spring Apps。 本文提供 Azure 應用程式閘道Azure Front Door,以及 Azure API 管理的特定 實作 指引,這是常用的反向 Proxy 服務。

注意

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

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

上下文

HTTP 要求的主機

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

重要

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

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

為何 Web 平臺使用主機名

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

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

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

說明 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。
  • Azure Spring Apps 使用類似的功能,強制執行 HTTPS。 它也會使用傳入主機來產生 HTTPS URL。
  • App Service 具有 ARR 親和性設定, 啟用黏性會話,讓來自相同瀏覽器實例的要求一律由相同的後端伺服器提供服務。 這是由 App Service 前端所執行,其會將 Cookie 新增至 HTTP 回應。 Cookie 的 Domain 會設定為傳入主機。
  • App Service 提供 驗證和授權功能,讓用戶輕鬆登入和存取 API 中的數據。

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

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

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

圖表,說明已覆寫主機名的組態。

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

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

潛在問題

不正確的絕對 URL

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

圖表,說明不正確的絕對 URL 問題。

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

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

重要

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

不正確的重新導向 URL

產生絕對重新導向 URL 時,會發生先前案例的常見且更具體的情況。 當您使用 OpenID Connect、Open Authorization (OAuth) 2.0 或安全性聲明標記語言 (SAML) 2.0 等瀏覽器型身分識別通訊協定時,Microsoft Entra ID 等身分識別服務需要這些 URL。 這些重新導向 URL 可由應用程式伺服器或中間件本身產生,或如先前所述,由應用程式服務等平臺功能 驗證和授權功能。 下圖說明問題:

圖表,說明不正確的重新導向 URL 問題。

  1. 瀏覽器會將 contoso.com 的要求傳送至反向 Proxy。
  2. 反向 Proxy 會將主機名重寫為對後端 Web 應用程式的要求 contoso.azurewebsites.net(或另一個服務的類似預設網域)。
  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 並使用傳入主機名來建構 Cookie的 屬性時,主機名不符也可能會導致問題。 Domain 屬性可確保 Cookie 只會用於該特定網域。 這些 Cookie 可由應用程式程式代碼產生,或如先前所述,由 app Service ARR 親和性設定等平臺功能產生。 下圖說明問題:

說明不正確 Cookie 網域的圖表。

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

常見 Azure 服務的實作指引

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

顯示保留主機名的組態的圖表。

後端組態

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

如果您在 App Service中裝載 Web 應用程式,則可以 將自定義功能變數名稱附加至 Web 應用程式,並避免在後端使用預設 azurewebsites.net 主機名。 當您將自定義網域附加至 Web 應用程式時,不需要變更 DNS 解析:您可以使用 記錄 來 驗證網域,而不會影響您的一般 記錄。 (這些記錄仍會解析為反向 Proxy 的IP位址。如果您需要端對端 TLS/SSL,您可以從 Key Vault 匯入現有的憑證,或使用自定義網域的 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)。

重要

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

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

注意

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

應用程式閘道

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

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

Azure Front Door

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

API 管理

根據預設,API 管理 會以 API Web 服務 URL 的主機組件覆寫傳送至後端的主機名(其對應至 APIResource Manager 定義的 值)。

您可以強制 API 管理改為使用傳入要求的主機名,方法是新增 inboundSet 標頭 原則,如下所示:

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

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

後續步驟