編輯

共用方式為


保留反向 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 DoorAzure 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 Azure Spring Apps 和 azure-api.net API 管理。

針對生產環境部署,您不會使用這些預設網域。 相反地,您可以提供自己的網域,以配合您的組織或應用程式的品牌。 例如, 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 中建立具有預設網域的 contoso.azurewebsites.netWeb 應用程式。 (或在 Azure 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

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

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

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

潛在問題

錯誤的絕對 URL

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

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

  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 Connect、Open Authorization (OAuth) 2.0 或安全性聲明標記語言 (SAML) 2.0 等瀏覽器型身分識別通訊協定時,Microsoft Entra ID 等身分識別服務需要這些 URL。 這些重新導向 URL 可由應用程式伺服器或中間件本身產生,或如先前所述,由應用程式服務 驗證和授權功能等平臺功能產生。 下圖說明問題:

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

  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 可由應用程式程式代碼產生,或如先前所述,由應用程式服務 ARR 親和性設定等平臺功能產生。 下圖說明問題:

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

  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 與後端應用程式伺服器之間的呼叫中保留原始主機名:

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

後端組態

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

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

注意

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

應用程式閘道

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

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

Azure Front Door

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

如果您使用 Azure Front Door Standard 或 Premium,您可以在原始定義中保留原始主機標頭空白來保留主機名。 在來源的 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 對主機名不符所造成的問題較不敏感,因此此組態可能不如重要。

下一步