使用应用程序网关重写 HTTP 标头和 URL
可以通过应用程序网关重写请求和响应的所选内容。 使用此功能,你可以转换 URL、查询字符串参数并修改请求标头和响应标头。 还可以通过它来添加条件,确保只有在满足特定条件的情况下才能重写 URL 或指定的标头。 这些条件基于请求和响应信息。
注意
HTTP 标头和 URL 重写功能仅适用于应用程序网关 v2 SKU
支持的重写类型
请求和响应标头
HTTP 标头可让客户端和服务器连同请求或响应一起传递附加的信息。 重写这些标头可以完成重要的任务,例如,添加安全相关的标头字段(如 HSTS/ X-XSS-Protection)、删除可能透露敏感信息的响应标头字段,以及从 X-Forwarded-For 标头中删除端口信息。
当请求和响应数据包在客户端与后端池之间移动时,可以通过应用程序网关添加、移除或更新 HTTP 请求和响应标头。
若要了解如何使用 Azure 门户在应用程序网关中重写请求标头和响应标头,请参阅此文。
支持的标头
可以重写请求和响应中的所有标头,但 Connection 和 Upgrade 标头除外。 还可以使用应用程序网关创建自定义标头,并将其添加到通过该网关路由的请求和响应。
URL 路径和查询字符串
利用应用程序网关中的 URL 重写功能,你可以:
重写请求 URL 的主机名、路径和查询字符串
选择重写侦听器上所有请求的 URL,或者只重写与所设置的一个或多个条件匹配的要求的 URL。 这些条件基于请求属性(请求头和服务器变量)。
选择基于原始 URL 或重写的 URL 来路由请求(选择后端池)
若要了解如何使用 Azure 门户在应用程序网关中重写 URL,请参阅此文。
重写操作
重写操作用于指定 URL。 请求要重写的标头或响应标头以及新的 URL 目标值。 URL 或者新标头或现有标头的值可设置为以下类型的值:
- 文本
- 请求标头。 若要指定请求标头,需使用语法 {http_req_headerName}
- 响应标头。 若要指定响应标头,需使用语法 {http_resp_headerName}
- 服务器变量。 若要指定服务器变量,需使用语法 {var_serverVariable}。 请参阅支持的服务器变量的列表
- 文本、请求标头、响应标头和服务器变量的组合。
重写条件
可以使用重写条件评估 HTTP 请求和响应的内容。 此可选配置允许仅在满足一个或多个条件时执行重写。 应用程序网关使用以下类型的变量来评估请求和响应的内容:
- 请求中的 HTTP 标头
- 响应中的 HTTP 标头
- 应用程序网关服务器变量
可以使用条件来评估指定的变量是否存在、指定的变量是否与特定的值匹配,或指定的变量是否与特定的模式匹配。
模式匹配
应用程序网关在条件中使用正则表达式进行模式匹配。 编写条件时,应使用与正则表达式 2 (RE2) 兼容的表达式。 如果使用核心规则集 3.1 或更低版本来运行应用程序网关 Web 应用程序防火墙 (WAF),则在使用 Perl 兼容正则表达式 (PCRE) 时可能会遇到问题。 使用 lookahead 和 lookbehind(负或正)断言时,可能会出现问题。
捕获
若要捕获子字符串供以后使用,请在条件正则表达式定义中用于匹配的子模式两侧加上括号。 第一对括号将其子字符串存储在 1 中,第二对则将其子字符串存储在 2 中,依此类推。 你可以根据需要使用任意多个括号;Perl 只需定义更多的编号变量供你用来表示这些捕获的字符串。 下面是参考文档中提供的一些示例:
(\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})。
如果要使用整个值,则不应提到编号。 直接使用 {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 客户端要访问的主机中的特定资源。 这是请求 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 | 客户端证书验证结果为:“成功”、“失败:<原因>”或“无”(如果不存在证书)。 |
重写配置
若要配置重写规则,需要创建重写规则集,并在其中添加重写规则配置。
重写规则集包含:
请求路由规则关联: 重写配置将通过路由规则关联到源侦听器。 使用基本路由规则时,重写配置与源侦听器相关联,并且是全局标头重写。 使用基于路径的路由规则时,将在 URL 路径映射中定义重写配置。 在这种情况下,该规则只会应用到站点的特定路径区域。 可以创建多个重写集,并将每个重写集应用于多个侦听器。 但是,对于一个特定的侦听器,只能应用一个重写集。
重写条件:此配置是可选的。 重写条件评估 HTTP(S) 请求和响应的内容。 如果 HTTP 请求或响应与重写条件匹配,则会发生重写操作。 如果将多个条件关联到一个操作,仅当满足所有条件时,才会发生该操作。 换言之,操作属于逻辑 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"
。
在此,只配置了标头重写,系统会在 "Accept" : "text/html"
上完成 WAF 评估。 但配置了 URL 重写或主机头重写时,则会在 "Accept" : "image/png"
上完成 WAF 评估。
标头重写的常见方案
从 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 标头中的主机名设置为应用程序网关的域名即可解决此问题。
下面是替换主机名的步骤:
创建一个重写规则,其中的某个条件可以评估响应中的 location 标头是否包含 chinacloudsites.cn。 输入模式
(https?):\/\/.*chinacloudsites\.cn(.*)$
。执行相应的操作来重写 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 路径设置为 buy.aspx
,将查询字符串设置为 category={var_uri_path_1}&product={var_uri_path_2}
有关如何实现上述方案的分步指南,请参阅使用 Azure 门户在应用程序网关中重写 URL
URL 重写与 URL 重定向
进行 URL 重写时,应用程序网关会在将请求发送到后端之前重写 URL。 这不会更改用户在浏览器中看到的内容,因为用户不会看到这些更改。
进行 URL 重定向时,应用程序网关会将包含新 URL 的重定向响应发送到客户端。 这样一来,客户端就必须将其请求重新发送到重定向中提供的新 URL。 用户在浏览器中看到的 URL 会更新为新的 URL。
限制
- 如果响应中包含多个同名的标头,则重写其中某个标头的值会导致删除该响应中的其他标头。 这种情况出现于 Set-Cookie 标头,因为在一个响应中可以包含多个 Set-Cookie 标头。 例如,如果将应用服务与应用程序网关一起使用,并在应用程序网关上配置了基于 Cookie 的会话关联,则就会出现此类情况。 在这种情况下,响应会包含两个 Set-Cookie 标头。 例如:应用服务会使用一个
Set-Cookie: ARRAffinity=ba127f1caf6ac822b2347cc18bba0364d699ca1ad44d20e0ec01ea80cda2a735;Path=/;HttpOnly;Domain=sitename.chinacloudsites.cn
,另一个Set-Cookie: ApplicationGatewayAffinity=c1a2bd51lfd396387f96bl9cc3d2c516; Path=/
用于应用程序网关相关性。 在此情况下重写其中一个 Set-Cookie 标头可能会导致从响应中删除另一个 Set-Cookie 标头。 - 当应用程序网关配置为重定向请求或显示自定义错误页时,不支持重写。
- 请求标头名称可以包含字母数字字符和连字符。 在将请求发送到后端目标时,将丢弃包含其他字符的标头名称。
- 响应头名称可以包含任何字母数字字符和 RFC 7230 中定义的特定符号。
- 无法重写 Connection 和 Upgrade 标头
- 直接从应用程序网关生成的 4xx 和 5xx 响应不支持重写