使用应用程序网关重写 HTTP 标头和 URL

可以通过应用程序网关重写请求和响应的所选内容。 使用此功能,你可以转换 URL、查询字符串参数并修改请求标头和响应标头。 还可以通过它来添加条件,确保只有在满足特定条件的情况下才能重写 URL 或指定的标头。 这些条件基于请求和响应信息。

HTTP 标头和 URL 重写功能仅适用于应用程序网关 v2 SKU

请求和响应标头

当请求和响应数据包在客户端与后端池之间移动时,可以通过应用程序网关添加、移除或更新 HTTP 请求和响应标头。 HTTP 标头可让客户端和服务器连同请求或响应一起传递附加的信息。 重写这些标头可以完成重要的任务,例如,添加安全相关的标头字段(如 HSTS/ X-XSS-Protection)、删除可能透露敏感信息的响应标头字段,以及从 X-Forwarded-For 标头中删除端口信息。

可以重写请求和响应中的所有标头,但 ConnectionUpgrade 标头除外。 还可以使用应用程序网关创建自定义标头,并将其添加到通过该网关路由的请求和响应。 若要了解如何使用 Azure 门户在应用程序网关中重写请求标头和响应标头,请参阅此文

显示请求和响应数据包中的标头的关系图。

URL 路径和查询字符串

利用应用程序网关中的 URL 重写功能,你可以:

  • 重写请求 URL 的主机名、路径和查询字符串

  • 选择重写侦听器上所有请求的 URL,或者只重写与所设置的一个或多个条件匹配的要求的 URL。 这些条件基于请求属性(请求头和服务器变量)。

  • 选择基于原始 URL 或重写的 URL 来路由请求(选择后端池)

若要了解如何使用 Azure 门户在应用程序网关中重写 URL,请参阅此文

此图描述了使用应用程序网关重写 URL 的过程。

了解应用程序网关中的重写

重写集是路由规则、条件和操作的集合。

  • 请求路由规则关联:重写配置将通过其路由规则关联到源侦听器。 使用“基本”类型的路由规则时,重写配置将与其侦听器相关联,并以全局重写的形式运行。 使用基于路径的路由规则时,将根据 URL 路径映射定义重写配置。 在后一种情况下,该规则只会应用于站点的特定路径区域。 可以将重写集应用于多个路由规则,但一个路由规则只能与一个重写相关联。

  • 重写条件:这是一个可选配置。 根据定义的条件,应用程序网关将评估 HTTP(S) 请求和响应的内容。 如果 HTTP(S) 请求或响应与重写条件匹配,则会发生后续的“重写操作”。 如果将多个条件关联到一个操作,仅当满足所有条件时,才会发生该操作。 换句话说,它是一个逻辑 AND 运算。 可以使用重写条件评估 HTTP 请求和响应的内容。 此可选配置允许仅在满足一个或多个条件时执行重写。 应用程序网关使用以下类型的变量来评估请求和响应的内容:

    可以选择以下类型来查找条件:

    使用条件可以评估指定的标头或变量是否存在,为此可以通过文本或正则表达式模式对其值进行匹配。 对于高级重写配置,还可以捕获标头或服务器变量的值,供稍后在重写操作中使用。 了解有关模式和捕获的详细信息。

  • 重写操作:使用重写操作集可以重写标头(请求或响应)或 URL 组件

    操作可以使用以下值类型或其组合:

    • Text。
    • 请求标头的值 - 要使用捕获的请求标头值,请将语法指定为 {http_req_headerName}
    • 响应标头的值 - 要使用从前面的条件中捕获的响应标头值,请将语法指定为 {http_resp_headerName}。 从操作集的“Set-Cookie”响应标头中捕获值时,可以使用 {capt_header_value_matcher}。 了解有关操作集下的捕获的详细信息。
    • 服务器变量 - 要使用服务器变量,请将语法指定为 {var_serverVariable}支持的服务器变量列表

    使用操作重写 URL 时,支持以下操作:

    • URL 路径:要设置为路径的新值。
    • URL 查询字符串:必须将查询字符串重写到的新值。
    • 重新评估路径映射:指定重写后是否必须重新评估 URL 路径映射。 如果保持未选中状态,则将使用原始 URL 路径来匹配 URL 路径映射中的路径模式。 如果设置为 true,则会重新评估 URL 路径映射,以检查它是否与重写的路径匹配。 启用此开关有助于在重写后将请求路由到不同的后端池。

模式匹配和捕获

支持在条件和操作下使用模式匹配和捕获(在操作下,仅支持对特定的标头使用)。

模式匹配

应用程序网关使用正则表达式进行模式匹配。 编写模式匹配语法时,应使用与正则表达式 2 (RE2) 兼容的表达式。

可以在条件和操作下使用模式匹配。

  • 条件:用于匹配标头或服务器变量的值。 若要匹配“条件”下的模式,请使用“pattern”属性。
  • 操作:操作集下的模式匹配仅适用于响应标头“Set-Cookie”。 若要匹配操作下的 Set-Cookie 模式,请使用“HeaderValueMatcher”属性。 如果已捕获,其值可以用作 {capt_header_value_matcher}。 由于可能存在多个 Set-Cookie,此处的模式匹配允许查找特定的 Cookie。 示例:对于特定版本的 user-agent,你想要使用 max-age=3600(一小时)重写“cookie2”的 set-cookie 响应标头。 在本例中,可以使用
    • 条件 - 类型:请求标头,标头名称:user-agent,要匹配的模式:*2.0
    • 操作 - 重写类型:响应标头,操作类型:设置,标头名称:Set-Cookie,标头值匹配器:cookie2=(.*),标头值:cookie2={capt_header_value_matcher_1};Max-Age=3600

注意

如果使用核心规则集 3.1 或更低版本来运行应用程序网关 Web 应用程序防火墙 (WAF),则在使用 Perl 兼容正则表达式 (PCRE) 时(此时也在执行先行和后行(负或正)断言)可能会遇到问题。

捕获语法

模式还可用于捕获子字符串供稍后使用。 请在正则表达式定义中的子模式两侧加上括号。 第一对括号将其子字符串存储在 1 中,第二对则将其子字符串存储在 2 中,依此类推。 你可以根据需要使用任意多个括号;Perl 只需定义更多的编号变量供你用来表示这些捕获的字符串。 可以在此 Perl 编程指南中找到一些示例。

  • (\d)(\d) # 匹配两个数字,将它们捕获到第 1 组和第 2 组中
  • (\d+) # 匹配一个或多个数字,将它们全部捕获到第 1 组中
  • (\d)+ #与一个数字匹配一次或多次,将最后一个捕获到第 1 组中

捕获后,可以使用以下格式在操作集值中使用它们:

  • 对于请求标头捕获,必须使用 {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}。 对于通过“HeaderValueMatcher”属性捕获的响应标头 Set-Cookie,必须使用 {capt_header_value_matcher_groupNumber}。 例如 {capt_header_value_matcher_1} 或 {capt_header_value_matcher_2}。
  • 对于服务器变量,必须使用 {var_serverVariableName_groupNumber}。 例如,{var_uri_path_1} 或 {var_uri_path_2}

注意

  • 不应在模式中指定使用 / 作为模式的前缀和后缀来匹配值。 例如,(\d)(\d) 将匹配两个数字。 /(\d)(\d)/ 不会匹配两个数字。
  • 条件变量的大小写需要与捕获变量的大小写匹配。 例如,如果条件变量是 User-Agent,则捕获变量必须为 User-Agent(即 {http_req_User-Agent_2})。 如果条件变量定义为 user-agent,则捕获变量必须为 user-agent(即 {http_req_user-agent_2})。
  • 如果要使用整个值,则不应提到编号。 直接使用 {http_req_headerName} 之类的格式,不带 groupNumber。

服务器变量

应用程序网关使用服务器变量来存储有关服务器、与客户端建立的连接以及对连接的当前请求的有用信息。 例如,存储的信息包括客户端的 IP 地址和 Web 浏览器类型。 服务器变量会动态更改,例如,加载新页或发布表单时就会更改。 可以使用这些变量来评估重写条件和重写标头。 若要使用服务器变量的值重写标头,需要在语法 {var_serverVariableName} 中指定这些变量

应用程序网关支持以下服务器变量:

变量名称 说明
add_x_forwarded_for_proxy X-Forwarded-For 客户端请求标头字段,其中追加了 IP1、IP2、IP3 等格式的 client_ip 变量(请参阅此表后面的解释)。 如果 X-Forwarded-For 字段不在客户端请求标头中,则 add_x_forwarded_for_proxy 变量等于 $client_ip 变量。 若要重写由应用程序网关设置的 X-Forwarded-For 标头,使该标头仅包含 IP 地址而不包含端口信息,则此变量很有用。
ciphers_supported 客户端支持的加密法列表。
ciphers_used 用于已建立 TLS 连接的加密法字符串。
client_ip 客户端的 IP 地址,应用程序网关从中接收请求。 如果应用程序网关和发起方客户端的前面有反向代理,则 client_ip 会返回该反向代理的 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 客户端要访问的主机中的特定资源。 变量引用任何操作之前的原始 URL 路径。 这是请求 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 连接的客户端证书的“颁发者 DN”字符串。
client_certificate_serial 用于已建立 SSL 连接的客户端证书的序列号。
client_certificate_start_date 客户端证书的开始日期。
client_certificate_subject 用于已建立 SSL 连接的客户端证书的“使用者 DN”字符串。
client_certificate_verification 客户端证书验证结果为:“成功”、“失败:<原因>”或“无”(如果不存在证书)。

标头重写的常见方案

从 X-Forwarded-For 标头中删除端口信息

应用程序网关先在所有请求中插入 X-Forwarded-For 标头,然后将请求转发到后端。 此标头是 IP 端口的逗号分隔列表。 在某些情况下,后端服务器只需在标头中包含 IP 地址。 你可以使用标头重写从 X-Forwarded-For 标头中删除端口信息。 若要这样做,一种做法是将该标头设置为 add_x_forwarded_for_proxy 服务器变量。 此外,也可使用变量 client_ip:

显示删除端口操作的屏幕截图。

修改重定向 URL

在某些情况下,修改重定向 URL 可能非常有用。 例如:客户端最初被重定向到“/blog”这样的路径,但由于内容结构的变化,现在应该被发送到“/updates”。

警告

在进行配置时,有时可能需要修改重定向 URL,由此,应用程序网关被配置为替代面向后端的主机名。 在这种情况下,后端看到的主机名与浏览器看到的主机名不同。 在这种情况下,重定向不会使用正确的主机名。 不建议使用此配置。

在反向代理与其后端 Web 应用程序之间保留原始 HTTP 主机名中介绍了此类配置的限制和影响。 对于应用服务,建议按照使用应用程序网关配置应用服务中的“自定义域(建议)”进行操作。 按以下示例所述重写响应中的 location 标头应被视为一种变通方法,但不能解决根本原因。

当应用服务发送重定向响应时,它会在其响应的位置标头中,使用它从应用程序网关收到的请求中的相同主机名。 因此,客户端会直接向 contoso.chinacloudsites.cn/path2 发出请求,而不是通过应用程序网关 (contoso.com/path2) 发出请求。 不应该绕过应用程序网关。

将 location 标头中的主机名设置为应用程序网关的域名即可解决此问题。

下面是替换主机名的步骤:

  1. 创建一个重写规则,其中的某个条件可以评估响应中的 location 标头是否包含 chinacloudsites.cn。 输入模式 (https?):\/\/.*chinacloudsites\.cn(.*)$

  2. 执行相应的操作来重写 location 标头,使其包含应用程序网关的主机名。 为此,请输入 {http_resp_Location_1}://contoso.com{http_resp_Location_2} 作为标头值。 此外,也可使用服务器变量 host 将主机名设置为与原始请求匹配。

    屏幕截图显示了修改位置标头操作。

实现安全 HTTP 标头以防止漏洞

在应用程序响应中实现必要的标头可以修复多个安全漏洞。 这些安全标头包括 X-XSS-Protection、Strict-Transport-Security 和 Content-Security-Policy。 可以使用应用程序网关为所有响应设置这些标头。

安全标头的屏幕显示。

删除不需要的标头

你可能想要从 HTTP 响应中删除透露敏感信息的标头。 例如,你可能想要移除后端服务器名称、操作系统或库详细信息等信息。 可以使用应用程序网关删除以下标头:

显示删除标头操作的屏幕截图。

无法创建重写规则来删除主机标头。 如果尝试创建重写规则,将该规则的操作类型设置为删除,并将标头设置为主机,则会导致错误。

检查某个标头是否存在

可以在 HTTP 请求或响应标头中评估某个标头或服务器变量是否存在。 如果你希望只有存在特定的标头时执行标头重写,则此评估非常有用。

显示标头操作的检查状态的屏幕显示。

URL 重写的常见方案

根据参数选择路径

若要完成根据标头的值、URL 的一部分或请求中的查询字符串选择后端池的方案,可以组合使用 URL 重写功能和基于路径的路由。

为此,请创建一个重写集,在其中包含检查特定参数(查询字符串、标头等)的条件然后执行更改 URL 路径的操作(确保启用重新评估路径映射)。 然后,必须将重写集关联到基于路径的规则。 基于路径的规则必须包含重写集中指定的相同 URL 路径及其相应的后端池。

因此,重写集允许用户检查特定参数并为其分配新路径,并且基于路径的规则允许用户将后端池分配到这些路径。 只要启用了“重新评估路径映射”,流量就会根据重写集中指定的路径进行路由。

有关使用查询字符串的用例示例,请参阅在门户中使用基于参数的路径选择来路由流量

基于 URL 重写查询字符串参数

假设有一个购物网站方案,其中的用户可见链接应简单明了,但后端服务器需要使用查询字符串参数来显示正确的内容。

在这种情况下,应用程序网关可以从 URL 中捕获参数,并从 URL 添加来自这些参数的查询字符串键值对。 例如,假设用户想要将 https://www.contoso.com/fashion/shirts 重写为 https://www.contoso.com/buy.aspx?category=fashion&product=shirts,则可通过以下 URL 重写配置来实现。

条件 - 如果服务器变量 uri_path 等于模式 /(.+)/(.+)

URL 重写方案 2-1。

操作 - 将 URL 路径设置为 buy.aspx,将查询字符串设置为 category={var_uri_path_1}&product={var_uri_path_2}

URL 重写方案 2-2。

有关如何实现上述方案的分步指南,请参阅使用 Azure 门户在应用程序网关中重写 URL

重写配置常见缺陷

  • 不允许对基本请求传递规则启用“重新评估路径映射”。 这是为了防止基本传递规则出现无限评估循环。

  • 需要至少有 1 个条件重写规则或 1 个没有为基于路基的传递规则启用“重新评估路径映射”的重写规则,以防止基于路径的传递规则出现无限评估循环。

  • 如果根据客户端输入动态创建了循环,则传入的请求会终止,并出现 500 错误代码。 在这种情况下,应用程序网关继续为其他请求提供服务,而不进行任何降级。

将 URL 重写或主机标头重写与 Web 应用程序防火墙结合使用 (WAF_v2 SKU)

配置 URL 重写或主机头重写时,WAF 评估会在修改请求头或 URL 参数之后(重写后)发生。 删除应用程序网关上的 URL 重写或主机头重写配置时,WAF 评估将在标头重写之前(重写前)完成。 此顺序可确保将 WAF 规则应用到后端池接收的最终请求。

例如,假设标头 "Accept" : "text/html" 具有以下标头重写规则 - 如果标头 "Accept" 的值等于 "text/html",则将该值重写为 "image/png"

在此,只配置了标头重写,系统会在 "Accept" : "text/html" 上完成 WAF 评估。 但配置了 URL 重写或主机头重写时,则会在 "Accept" : "image/png" 上完成 WAF 评估。

URL 重写与 URL 重定向

进行 URL 重写时,应用程序网关会在将请求发送到后端之前重写 URL。 这不会更改用户在浏览器中看到的内容,因为用户不会看到这些更改。

进行 URL 重定向时,应用程序网关会将包含新 URL 的重定向响应发送到客户端。 这样一来,客户端就必须将其请求重新发送到重定向中提供的新 URL。 用户在浏览器中看到的 URL 会更新为新的 URL。

重写与重定向。

限制

  • 当应用程序网关配置为重定向请求或显示自定义错误页时,不支持重写。
  • 请求标头名称可以包含字母数字字符和连字符。 在请求发送到后端目标时,包含其他字符的标头名称将会被丢弃。
  • 响应头名称可以包含任何字母数字字符和 RFC 7230 中定义的特定符号。
  • 无法重写 Connection 和 Upgrade 标头
  • 直接从应用程序网关生成的 4xx 和 5xx 响应不支持重写

后续步骤