IIS CGI HTTP_PROXY 标头请求可能被重定向

症状

使用 IIS 公共网关接口 (CGI) 功能托管使用某个库重定向请求的可执行程序时,请求可能会因存在“PROXY”请求标头而受误导。已知若干 Web 应用程序平台在使用此库。其中包括 PHP、Python 和 Go 等平台。

原因

CGI 是允许 Web 服务器托管作为可执行程序运行的应用程序的接口。Web 服务器接收到请求时,此服务器启动新的进程处理这个请求。此请求完成时,退出进程。为了使进程有权访问请求数据,具有名称前缀“HTTP_”的环境变量会包括请求标头。因此,包含名为“Proxy”的标头的请求的 CGI 进程具有“HTTP_PROXY”环境变量,值与请求标头相同。

cURL 命令行和库通常用于支持各种应用程序向各种服务器(包括 Web 服务器)发出请求。此库可以通过使用命令行参数进行配置,也可以从主机进程环境变量中读取其配置参数。“HTTP_PROXY”是 cURL 所使用的众多配置参数之一。“HTTP_PROXY”由 cURL 用来通过配置代理发送 HTTP 请求。

注意 这与以“HTTP_PROXY”表示的客户端请求标头无关。

cURL 托管在 CGI 进程内并且此进程包含名为“HTTP_PROXY”的环境变量时,cURL 使用其值通过 HTTP 代理(其值在环境变量中指定)发送请求数据。之所以出现此问题,是因为 cURL 预期“HTTP_PROXY”是配置指令而非客户端请求标头。

替代方法

若要解决此问题,请不要在运行 IIS 的服务器上使用 CGI。CGI 是一个大型弃用接口,将由更新且更为性能相关的接口替代。具体而言,PHP、Python 和 Go 应通过 IIS 上的 FastCGI 托管。FastCGI 不将环境变量用于客户端请求标头,因此不存在此问题。然而对于 PHP,一些应用程序可能会使用 PHP 的 getenv() 函数来检索环境变量。即使 PHP 未托管在 CGI 进程内时,也会通过将请求标头值插入提供给 PHP 的 getenv() 函数的数据集来复制 CGI 行为。如果使用 PHP 应用程序以此方式检索 HTTP_PROXY,以下清除此标头值或拒绝 PROXY 标头请求的缓解措施是有效的。

如果出于某种原因而必须使用 CGI,则会阻止包含名为“Proxy”的请求标头的请求或清除该标头的值。这是因为“Proxy”并不是标准的请求标头名称,而且浏览器通常不会发送此标头。

若要阻止包含 Proxy 标头的请求(首选解决方案),请运行以下命令行:
appcmd set config /section:requestfiltering /+requestlimits.headerLimits.[header='proxy',sizelimit='0']

注意 appcmd.exe 并非通常位于此路径下,也可能在 %systemroot%\system32\inetsrv 目录中找到。

若要清除标头的值,可以使用以下 URL Rewrite 规则:
<system.webServer>
<rewrite>
<rules>
<rule name="Erase HTTP_PROXY" patternSyntax="Wildcard">
<match url="*.*" />
<serverVariables>
<set name="HTTP_PROXY" value="" />
</serverVariables>
<action type="None" />
</rule>
</rules>
</rewrite>
</system.webServer>

注意 URL Rewrite 是 IIS 的一个可下载插件,并不包括在默认的 IIS 安装中。
属性

文章 ID:3179800 - 上次审阅时间:2016年8月2日 - 修订版本: 1

反馈