使用应用程序网关重写 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 标头的“标头值匹配程序”字段。 此可选字段使你可以在存在多个同名的 Set-Cookie 标头时匹配特定标头并捕获特定标头的值。 若要操作该特定 Cookie 的捕获值,可以使用 {capt_header_value_matcher}。 了解有关操作集下的捕获的详细信息。
    • 服务器变量 - 要使用服务器变量,请将语法指定为 {var_serverVariable}支持的服务器变量列表

注意

当前不支持通过门户使用“标头值匹配器”字段 {capt_header_value_matcher}。 因此,如果要使用此字段,则需继续使用非门户方法进行任何 PUT 操作。

使用操作重写 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代理) X-Forwarded-For 客户端请求标头字段,其中追加了 IP1、IP2、IP3 等格式的 client_ip 变量(请参阅此表后面的解释)。 如果 X-Forwarded-For 字段不在客户端请求标头中,则 add_x_forwarded_for_proxy 变量等于 $client_ip 变量。 若要重写由应用程序网关设置的 X-Forwarded-For 标头,使该标头仅包含 IP 地址而不包含端口信息,则此变量很有用。
支持的密码 客户端支持的加密法列表。
使用的密码 用于已建立 TLS 连接的加密法字符串。
客户端IP地址 客户端的 IP 地址,应用程序网关从中接收请求。 如果应用程序网关和发起方客户端的前面有反向代理,则 client_ip 会返回该反向代理的 IP 地址。
客户端端口 客户端端口。
client_tcp_rtt 有关客户端 TCP 连接的信息。 在支持 TCP_INFO 套接字选项的系统上可用。
client_user 使用 HTTP 身份验证时提供用于身份验证的用户名。
主机 按此优先顺序排列:请求行中的主机名、Host 请求标头字段中的主机名,或与请求匹配的服务器名称。 示例:在请求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam 中,主机值为 contoso.com
cookie_name name Cookie。
HTTP方法 用于发出 URL 请求的方法。 例如 GET 或 POST。
HTTP状态 会话状态。 例如 200、400 或 403。
http_version 请求协议。 通常为 HTTP/1.0、HTTP/1.1 或 HTTP/2.0。
查询字符串 请求的 URL 中“?”后面的变量/值对列表。 示例:在请求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam 中,query_string 值为 id=123&title=fabrikam
接收字节 请求的长度(包括请求行、标头和请求正文)。
request_query 请求行中的参数。
请求方案 请求方案:http 或 https。
请求_URI 完整的原始请求 URI(带参数)。 示例:在请求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam* 中,request_uri 值为 /article.aspx?id=123&title=fabrikam
已发送字节数 发送到客户端的字节数。
server端口 接受请求的服务器端口。
SSL连接协议 已建立的 TLS 连接的协议。
SSL已启用 如果连接在 TLS 模式下建立,则为“On”。 否则为空字符串。
URI路径 标识 Web 客户端要访问的主机中的特定资源。 变量引用任何操作之前的原始 URL 路径。 这是请求 URI 中没有参数的部分。 例如,在请求 http://contoso.com:8080/article.aspx?id=123&title=fabrikam 中,uri_path 值为 /article.aspx

相互身份验证服务器变量

应用程序网关支持将以下服务器变量用于相互身份验证方案。 使用这些服务器变量的方式与上面用于其他服务器变量的方式相同。

变量名称 说明
客户端证书 已建立的 SSL 连接的客户端证书,采用 PEM 格式。
客户证书终止日期 客户端证书的结束日期。
客户端证书指纹 用于已建立 SSL 连接的客户端证书的 SHA1 指纹。
客户端证书颁发者 用于已建立 SSL 连接的客户端证书的“颁发者 DN”字符串。
客户端证书序列号 用于已建立 SSL 连接的客户端证书的序列号。
客户证书开始日期 客户端证书的开始日期。
客户端证书主体 用于已建立 SSL 连接的客户端证书的“使用者 DN”字符串。
客户端证书验证 客户端证书验证结果为:“成功”、“失败:原因<”或“无”(如果不存在证书)。

标头重写的常见方案

从 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 中定义的特定符号。
  • 无法重写 X-Original-Host、Connection 和 Upgrade 标头
  • 直接从应用程序网关生成的 4xx 和 5xx 响应不支持重写

后续步骤