使用應用程式閘道重寫 HTTP 標頭和 URL

應用程式閘道可讓您重寫所選的要求和回應內容。 您可以使用這項功能來轉譯 URL、查詢字串參數,以及修改要求和回應標頭。 您還可以新增條件,以確保僅在符合特定條件時,才重寫 URL 或指定的標頭。 這些條件所根據的是要求和回應資訊。

注意

HTTP 標頭和 URL 重寫功能僅適用於應用程式閘道 v2 SKU

支援的重寫類型

要求和回應標頭

HTTP 標頭可讓用戶端和伺服器透過要求或回應傳遞其他資訊。 您可以重寫這些標頭來完成重要的工作,例如新增安全性相關的標頭欄位 (例如 HSTS/ X-XSS-Protection)、移除可能洩露敏感性資訊的回應標頭欄位,以及從 X-Forwarded-For 標頭中移除連接埠資訊。

應用程式閘道可讓您在要求和回應封包於用戶端與後端集區之間移動時,新增、移除或更新 HTTP 要求和回應標頭。

若要瞭解如何使用 Azure 入口網站與應用程式閘道重寫要求和回應標頭,請參閱這裡

img

支援的標頭

您可以重寫要求和回應中的所有標頭,但連線和升級標頭除外。 您也可以使用應用程式閘道來建立自訂標頭,並將其新增至透過其路由傳送的要求和回應。

URL 路徑和查詢字串

應用程式閘道中的 URL 重寫功能可讓您:

  • 重寫要求 URL 的主機名稱、路徑和查詢字串

  • 選擇重寫接聽程式上所有要求的 URL,或只重寫符合您設定的一或多個條件的要求。 這些條件以要求屬性為基礎 (要求標頭和伺服器變數)。

  • 選擇根據原始 URL 或重寫的 URL 來路由傳送要求 (選取後端集區)

若要瞭解如何使用 Azure 入口網站與應用程式閘道重寫 URL,請參閱這裡

Diagram that describes the process for rewriting a URL with Application Gateway.

重寫動作

使用重寫動作來指定您要重寫的 URL、要求標頭或回應標頭,以及您想要重寫成什麼新的值。 URL 或新的或現有標頭的值可以設定為這幾種值:

  • Text
  • 要求標頭。 若要指定要求標頭,您必須使用語法 {http_req_headerName}
  • 回應標頭。 若要指定回應標頭,您必須使用語法 {http_resp_headerName}
  • 伺服器變數。 若要指定伺服器變數,您必須使用 {var_serverVariable} 語法。 請參閱支援的伺服器變數清單
  • 文字、要求標頭、回應標頭和伺服器變數的組合。

重寫條件

您可以使用重寫條件 (選用設定) 來評估 HTTP(S) 要求和回應的內容,並只在符合一或多個條件時,才執行重寫。 應用程式閘道使用這幾種變數來評估要求和回應的內容:

  • 要求中的 HTTP 標頭
  • 回應中的 HTTP 標頭
  • 應用程式閘道伺服器變數

您可以使用條件來評估指定的變數是否存在、指定的變數是否符合特定的值,或指定的變數是否符合特定模式。

模式比對

應用程式閘道使用規則運算式來比對條件中的模式。 撰寫條件時,您應該使用與規則運算式 2 (RE2) 相容的運算式。 如果您要使用核心規則集 3.1 或更早版本執行應用程式閘道 Web 應用程式防火牆 (WAF),則在使用與 Perl 相容的規則運算式 (PCRE) (英文) 時 (同時執行右合樣和左合樣 (負值或正值) 判斷提示) 可能會遇到問題。

擷取

若要擷取子字串以供稍後使用,請將括弧放在將其比對於條件 RegEx 定義的子模式周圍。 第一對括弧會將其子字串儲存在 1 中,而第二對會儲存在 2,以此類推。 您可以視需要使用多個括弧;Perl 只會持續定義更多編號的變數,讓您呈現這些擷取的字串。 ref 的一些範例:

  • (\d)(\d) # 比對兩位數字,將其擷取至群組 1 和 2

  • (\d+) # 比對一或多個數字,將所有位數擷取至群組 1

  • (\d+) # 比對一或多次,將最後一次擷取至群組 1

注意

使用 / 來加上首碼和尾碼時,模式不應在模式中指定以比對值。 例如,(\d)(\d) 會比對兩位數字。 /(\d)(\d)/ 不會比對兩位數字。

擷取之後,您可以使用下列格式在動作集中參考這些數字:

  • 對於要求標頭擷取,您必須使用 {HTTP_req_headerName_groupNumber}。 例如,{HTTP_req_User-Agent_1} 或 {HTTP_req_User-Agent_2}
  • 對於回應標頭擷取,您必須使用 {HTTP_resp_headerName_groupNumber}。 例如,{HTTP_resp_Location_1} 或 {HTTP_resp_Location_2}
  • 對於伺服器變數,您必須使用 {var_serverVariableName_groupNumber}。 例如,{var_uri_path_1} 或 {var_uri_path_2}

注意

條件變數的大小寫必須符合擷取變數的大小寫。 例如,如果我的條件變數是 User-Agent,則我的擷取變數必須為 User-Agent (也就是 {HTTP_req_User-Agent_2})。 如果我的條件變數定義為 user-agent,則我的擷取變數必須為 user-agent (也就是 {HTTP_req_user-agent_2})。

如果您想要使用整個值,則不應該提及數字。 單純使用 {HTTP_req_headerName} 格式之類,而不使用 groupNumber。

伺服器變數

應用程式閘道會使用伺服器變數來儲存伺服器、與用戶端的連線,以及連線上目前要求的相關實用資訊。 儲存的資訊範例包括用戶端的 IP 位址和網頁瀏覽器類型。 例如,當新頁面載入或張貼表單時,伺服器變數會動態地變更。 您可以使用這些變數來評估重寫條件和重寫標頭。 若要使用伺服器變數的值來重寫標頭,您必須在語法 {var_serverVariableName} 中指定這些變數

應用程式閘道支援下列伺服器變數:

變數名稱 描述
add_x_forwarded_for_proxy 以 IP1、IP2、IP3 等格式附加 client_ip 變數的 X-Forwarded-For 用戶端要求標頭欄位 (請參閱下表稍後的說明)。 如果 X-Forwarded-For 欄位不在用戶端要求標頭中,則 add_x_forwarded_for_proxy 變數等於 $client_ip 變數。 當您想要重寫應用程式閘道設定的 X-Forwarded-For header 標頭時,此變數會特別有用,如此可讓標頭只包含 IP 位址,而不包含連接埠資訊。
ciphers_supported 用戶端支援的加密清單。
ciphers_used 用於所建立 TLS 連線的加密字串。
client_ip 應用程式閘道接收要求所在用戶端的 IP 位址。 如果應用程式閘道和原始用戶端之前有反向 Proxy,client_ip 將會傳回反向 Proxy 的 IP 位址。
client_port 用戶端連接埠。
client_tcp_rtt 用戶端 TCP 連線的相關資訊。 適用於支援 TCP_INFO 通訊端選項的系統。
client_user 使用 HTTP 驗證時,提供用於驗證的使用者名稱。
host 優先順序如下:來自要求行的主機名稱、來自 Host 要求標頭欄位的主機名稱,或是與要求相符的伺服器名稱。 例如,在要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam 中,主機值將會是 contoso.com
cookie_name name Cookie。
http_method 用來提出 URL 要求的方法。 例如,GET 或 POST。
http_status 工作階段狀態。 例如,200、400 或 403。
http_version 要求通訊協定。 通常是 HTTP/1.0、HTTP/1.1 或 HTTP/2.0。
query_string 接在所要求 URL 中「?」後面的變數/值組清單。 範例:在要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam 中,query_string 值將會是 id=123&title=fabrikam
received_bytes 要求的長度 (包括要求行、標頭和要求本文)。
request_query 要求行中的引數。
request_scheme 要求結構配置:http 或 https。
request_uri 完整的原始要求 URI (含引數)。 範例:在要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam* 中,request_uri 值將會是 /article.aspx?id=123&title=fabrikam
sent_bytes 傳送給用戶端的位元組數。
server_port 已接受要求的伺服器連接埠。
ssl_connection_protocol 所建立 TLS 連線的通訊協定。
ssl_enabled 如果連線以 TLS 模式運作,則為「On」。 否則便為空字串。
uri_path 識別 Web 用戶端想要存取主機中的特定資源。 這是要求 URI 中不含引數的部分。 範例:在要求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam 中,uri_path 值將會是 /article.aspx

相互驗證伺服器變數

應用程式閘道支援下列用於相互驗證案例的伺服器變數。 使用這些伺服器變數的方式與其他伺服器變數相同。

變數名稱 描述
client_certificate 用於已建立 SSL 連線的 PEM 格式用戶端憑證。
client_certificate_end_date 用戶端憑證的結束日期。
client_certificate_fingerprint 用於已建立 SSL 連線的用戶端憑證 SHA1 指紋。
client_certificate_issuer 用於已建立 SSL 連線的用戶端憑證「issuer DN」字串。
client_certificate_serial 用於已建立 SSL 連線的用戶端憑證序號。
client_certificate_start_date 用戶端憑證的開始日期。
client_certificate_subject 用於已建立 SSL 連線的用戶端憑證「subject DN」字串。
client_certificate_verification 用戶端憑證驗證的結果:「成功」、「失敗:<原因>」,或如果憑證不存在,則為「無」

重寫設定

若要設定重寫規則,您必須建立重寫規則集,並在其中新增重寫規則設定。

重寫規則集包含:

  • 要求路由規則關聯:重寫設定會透過路由規則,與來源接聽程式相關聯。 使用基本路由規則時,重寫設定會與來源接聽程式相關聯,而且是全域標頭重寫。 使用路徑式路由規則時,則是在 URL 路徑對應上定義重寫設定。 在此情況下,僅適用於網站的特定路徑區域。 您可以建立多個重寫集,並將每個重寫集套用至多個接聽程式。 但您只能將一個重寫集套用至一個特定接聽程式。

  • 重寫條件:這是選用設定。 重寫條件會評估 HTTP(S) 要求和回應的內容。 如果 HTTP(S) 要求或回應符合重寫條件,將會執行重寫動作。 如果您將多個條件與某個動作產生關聯,則只有在符合所有條件時,才會執行此動作。 換句話說,這是一種邏輯 AND 運算。

  • 重寫類型:有 3 種類型的重寫可用:

    • 重寫要求標頭
    • 重寫要求標頭
    • 重寫 URL 元件
      • URL 路徑:將路徑重寫為此值。
      • URL 查詢字串:將查詢字串重寫為此值。
      • 重新評估路徑對應:用來判斷是否重新評估 URL 路徑對應。 如果保持未核取,則會使用原始 URL 路徑來比對 URL 路徑對應中的路徑模式。 如果設定為 true,則會重新評估 URL 路徑對應,以檢查是否符合重寫路徑。 啟用此參數有助於在重寫後將要求路由傳送至不同的後端集區。

重寫設定的常見陷阱

  • 基本要求路由規則不允許啟用「重新評估路徑對應」。 這是為了避免基本路由規則的無限評估迴圈。

  • 必須至少有 1 個條件式重寫規則,或 1 個重寫規則未針對路徑型路由規則啟用「重新評估路徑對應」,以防止路徑型路由規則的無限評估迴圈。

  • 如果根據用戶端輸入動態建立迴圈,傳入要求會以 500 錯誤碼終止。 應用程式閘道會繼續提供其他要求,而不會在此類案例中降級。

使用 URL 重寫或主機標頭重寫搭配 Web 應用程式防火牆 (WAF_v2 SKU)

當您設定 URL 重寫或主機標頭重寫時,WAF 評估會在修改要求標頭或 URL 參數之後 (重寫後) 發生。 當您移除應用程式閘道上的 URL 重寫或主機標頭重寫設定時,WAF 評估會在標頭重寫 (重寫前) 之前完成。 此順序可確保 WAF 規則會套用至後端集區所接收的最終要求。

例如,假設您有標頭 "Accept" : "text/html" 的下列標頭重寫規則 - 如果標頭 "Accept" 的值等於 "text/html",請將值重寫為 "image/png"

在這裡,只有已設定的標頭重寫,WAF 評估將會在 "Accept" : "text/html" 上完成。 但是當您設定 URL 重寫或主機標頭重寫時,WAF 評估會在 "Accept" : "image/png" 上完成。

標頭重寫的常見案例

從 X-Forwarded-For 標頭中移除連接埠資訊

應用程式閘道會將 X-Forwarded-For 標頭插入所有要求,再將要求轉送至後端。 此標頭是以逗號分隔的 IP 連接埠清單。 在某些情況下,後端伺服器只需要標頭來包含 IP 位址。 您可以使用標頭重寫,以從 X-Forwarded-For 標頭中移除連接埠資訊。 其中一種方法是將標頭設定為 add_x_forwarded_for_proxy 伺服器變數。 或者,您也可以使用變數 client_ip:

Remove port

修改重新導向 URL

在某些情況下,重新導向 URL 的修改可能會很有用。 例如:用戶端原本已重新導向至「/blog」之類的路徑,但現在應該因為內容結構的變更而傳送至「/updates」。

警告

有時候,修改重新導向 URL 的需求會出現在設定的內容中,其中應用程式閘道設定為覆寫後端的主機名稱。 後端所見的主機名稱與瀏覽器所見的主機名稱不同。 在此情況下,重新導向不會使用正確的主機名稱。 我們不建議這種設定。

此類設定的限制和影響如在反向 Proxy 及其後端 Web 應用程式之間保留原始 HTTP 主機名稱中所述。 App Service 的建議設定是遵循使用應用程式閘道設定 App Service 中的「自訂網域 (建議)」指示。 如下列範例所述,重寫回應上的位置標頭應該視為因應措施,而且無法解決根本原因。

當 App Service 傳送重新導向回應時,會在其回應的位置標頭中使用與其從應用程式閘道所接收要求中主機名稱相同的主機名稱。 因此,用戶端會直接對 contoso.azurewebsites.net/path2 提出要求,而非透過應用程式閘道 (contoso.com/path2)。 不需要略過應用程式閘道。

您可以將位置標頭中的主機名稱設定為應用程式閘道的網域名稱,以解決此問題。

以下是取代主機名稱的步驟:

  1. 使用條件建立重寫規則,以評估回應中的位置標頭是否包含 azurewebsites.net。 輸入模式 (https?):\/\/.*azurewebsites\.net(.*)$
  2. 執行動作來重寫位置標頭,使其具有應用程式閘道的主機名稱。 輸入 {http_resp_Location_1}://contoso.com{http_resp_Location_2} 作為標頭值來執行此動作。 或者,您也可以使用伺服器變數 host 來設定主機名稱以符合原始要求。

Modify location header

實作安全性 HTTP 標頭以防止弱點

您可以在應用程式回應中實作必要的標頭,以修正數個安全性弱點。 這些安全性標頭包括 X-XSS-Protection、Strict-Transport-Security 和 Content-Security-Policy。 您可以使用應用程式閘道來設定所有回應的這些標頭。

Security header

刪除不必要的標頭

您可能想要從 HTTP 回應中移除顯示敏感性資訊的標頭。 例如,您可能想要移除後端伺服器名稱、作業系統或程式庫詳細資料等資訊。 您可以使用應用程式閘道來移除這些標頭:

Deleting header

檢查標頭是否存在

您可以評估 HTTP 要求或回應標頭,以瞭解標頭或伺服器變數是否存在。 您想要僅在特定標頭存在才執行標頭重寫時,此評估相當實用。

Checking presence of a header

URL 重寫的常見案例

參數型路徑選取

若要完成您想要根據標頭、URL 部分或要求中查詢字串的值來選擇後端集區的案例,您可以使用 URL 重寫功能和路徑型路由的組合。 例如,如果您有購物網站,且產品類別是以 URL 中查詢字串的形式傳遞,而您想要根據查詢字串將要求路由傳送至後端,則:

步驟 1:建立路徑對應,如下圖所示

URL rewrite scenario 1-1.

步驟 2 (a):建立具有 3 個重寫規則的重寫集合:

  • 第一個規則有一個條件,該條件會檢查 category=shoesquery_string 變數,且具有重寫 /listing1 URL 路徑並啟用重新評估路徑對應的動作

  • 第二個規則有一個條件,該條件會檢查 category=bagsquery_string 變數,且具有重寫 /listing2 URL 路徑並啟用重新評估路徑對應的動作

  • 第三個規則有一個條件,該條件會檢查 category=accessoriesquery_string 變數,並具有重寫 /listing3 URL 路徑並啟用重新評估路徑對應的動作

URL rewrite scenario 1-2.

步驟 2 (b):將此重寫集合與上述路徑型規則的預設路徑建立關聯

URL rewrite scenario 1-3.

現在,如果使用者要求 contoso.com/listing?category=any,則會比對預設路徑,因為路徑對應中沒有任何路徑模式 (/listing1、/listing2、/listing3) 相符。 由於您將上述重寫集合與此路徑建立關聯,因此會評估此重寫集合。 由於查詢字串不會比對此重寫集合中任何 3 個重寫規則的條件,因此不會執行任何重寫動作,且要求會路由傳送至與預設路徑相關聯的後端 (也就是 GenericList)。

如果使用者要求 contoso.com/listing?category=shoes,則會再次比對預設路徑。 不過,在此情況下,第一個規則中的條件將會相符,因此會執行與條件相關聯的動作,以重寫 /listing1 的 URL 路徑,並重新評估 path-map。 重新評估路徑對應時,要求現在會比對與模式 /listing1 相關聯的路徑,而要求將會路由傳送至與此模式相關聯的後端,也就是 ShoesListBackendPool。

注意

此案例可以根據定義的條件,延伸至任何標頭或 Cookie 值、URL 路徑、查詢字串或伺服器變數,基本上可讓您根據這些條件來路由傳送要求。

根據 URL 重寫查詢字串參數

請考慮購物網站的案例,其中使用者可見連結應該是簡單易懂的,但後端伺服器需要查詢字串參數來顯示正確的內容。

在此情況下,應用程式閘道可以從 URL 擷取參數,並從 URL 新增查詢字串索引鍵/值組。 例如,假設使用者想要從 https://www.contoso.com/fashion/shirts 重寫至 https://www.contoso.com/buy.aspx?category=fashion&product=shirts,則可以透過下列 URL 重寫設定來達成。

條件 - 如果伺服器變數 uri_path 等於模式 /(.+)/(.+)

URL rewrite scenario 2-1.

動作 - 將 URL 路徑設定為 buy.aspx,並將查詢字串設定為 category={var_uri_path_1}&product={var_uri_path_2}

URL rewrite scenario 2-2.

如需達成上述案例的逐步指南,請參閱使用 Azure 入口網站與應用程式閘道重寫 URL

URL 重寫與 URL 重新導向

針對 URL 重寫,應用程式閘道會在要求傳送至後端之前重寫 URL。 這不會變更使用者在瀏覽器中看到的內容,因為變更會向使用者隱藏。

針對 URL 重新導向,應用程式閘道會使用新的 URL 將重新導向回應傳送至用戶端。 接著,用戶端必須將其要求重新傳送至重新導向中提供的新 URL。 使用者在瀏覽器中看到的 URL 將會更新為新的 URL。

Rewrite vs Redirect.

限制

  • 如果回應有多個具有相同名稱的標頭,則重寫其中一個標頭的值會導致在回應中卸除其他標頭。 這通常發生在Set-Cookie標頭中,因為您可以在回應中有多個 Set-Cookie 標頭。 其中一種案例是當您搭配應用程式閘道使用應用程式服務,並在應用程式閘道上設定 Cookie 型工作階段親和性時。 在此情況下,回應會包含兩個 Set-Cookie 標頭:一個由應用程式服務使用,例如:Set-Cookie: ARRAffinity=ba127f1caf6ac822b2347cc18bba0364d699ca1ad44d20e0ec01ea80cda2a735;Path=/;HttpOnly;Domain=sitename.azurewebsites.net 以及另一個用於應用程式閘道親和性,例如 Set-Cookie: ApplicationGatewayAffinity=c1a2bd51lfd396387f96bl9cc3d2c516; Path=/。 在此案例中重寫其中一個 Set-Cookie 標頭,可能會導致從回應中移除另一個 Set-Cookie 標頭。
  • 當應用程式閘道設定為重新導向要求或顯示自訂錯誤頁面時,不支援重寫。
  • 要求標頭名稱可以包含英數字元和連字號。 當要求傳送至後端目標時,將會捨棄包含其他字元的標頭名稱。
  • 回應標頭名稱可以包含任何英數字元和 RFC 7230 (英文) 中所定義的特定符號。
  • 無法重寫連線和升級標頭
  • 重寫不支援直接從應用程式閘道產生的 4xx 和 5xx 回應

下一步