我有一个带有 ARR 3.0 和 URL 重写模块 2.1 的 IIS10 服务器,它充当其他几个 Web 服务器的反向代理。其他服务器运行在不同的端口上,因此 IIS10 服务器在端口 80 上提供“友好 URL”。 URL 重写用于将请求交给后端服务器。
这样的服务器之一是 Jenkins。
Jenkins 有一条警告消息,告诉您反向代理是否配置良好(此处有更多详细信息),此警告消息帮助我找到了反向代理中的问题。
问题是 URL 重写正在对我的 URL 进行解码和编码,当它们到达 Jenkins 时,它们与浏览器请求的不同。
示例:
URL重写规则:
<rule name="Jenkins Rewrite" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern=".*jenkins.mydomain.*" />
<add input="{HTTPS}" pattern="on" />
</conditions>
<action type="Rewrite" url="http://localhost:8080/{R:1}" appendQueryString="true" />
<serverVariables>
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
<set name="HTTP_X_FORWARDED_SCHEMA" value="https" />
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
</serverVariables>
</rule>
发送以下网址时:
我注意到编码字符在触发规则之前被解码,使得 {R:1} 看起来像这样:
/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https:/jenkins.mydomain/manage/
经过一番研究,我发现我可以使用 {UNENCODED_URL} 而不是 {R:1} 在解码之前获取请求字符串,所以我调整了我的规则操作:
<action type="Rewrite" url="http://localhost:8080{UNENCODED_URL}" appendQueryString="false" />
不幸的是,URL Rewrite 在我的 Rewrite 之后再次对 URL 进行编码,使得 Jenkins 收到的 URL 被双重编码:
/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%253A%252F%252Fjenkins.mydomain%252Fmanage%253F
简短摘要:
当您查看此网址时:
/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F
我们拥有的是:
/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/<parameter1>
哪里
<parameter1> = https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F
<parameter1>
中的斜杠字符被编码,以便Jenkins可以知道path
的一部分以及<parameter1>
是什么。
这意味着,当 URL 重写解码 URL 时,
<parameter1>
会与 path
的其余部分混合。
期望的结果是获取与浏览器发送的 URL 完全相同的 URL,但指向本地主机:
http://localhost:8080/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F
是否有办法禁用 URL 重写模块正在执行的解码/编码操作?
PS:我发现了一篇关于 URL Rewrite v2.1 功能的博客文章,它说有一个新标志可用于禁用此行为,但我不知道如何或在哪里设置它。
在 v7.1.1980 之前的 URL 重写版本中,当尝试使用 UNENCODED_URL,URL重写会对它进行编码,这可能会导致双重 如果原始 URL 已经编码,则进行编码 这是违规的 RFC3986 第 2.4 节的规定,其中规定“实现不得 对同一字符串进行多次百分比编码或解码,如解码 已解码的字符串可能会导致错误解释百分比数据 八位字节作为百分比编码的开头,反之亦然 对已经进行百分比编码的字符串进行百分比编码的情况。” 使得 UNENCODED_URL 的使用变得不切实际,尤其是在反向时 具有 ARR 的转发器场景,其中后端服务器需要 URL 不加修改地通过。
在 v7.1.1980 中,我们添加了一个功能标志,useOriginalURLEncoding 允许您在设置时关闭此不兼容的 URL 编码 为真。默认行为将保持不变 (useOriginalURLEncoding 默认为 true)。
这里有人知道如何做吗?
我设法通过设置我在问题中引用的帖子中描述的
useOriginalURLEncoding = false
解决了这个问题。
要将标志设置为
IIS Manager
,然后选择 Configuration Editor
并转到 system.webServer/rewrite/rules
部分,您将在其中找到 useOriginalURLEncoding
标志。
将该标志设置为 false,当在规则中使用
{UNENCODED_URL}
变量时,URL 重写将不再对 URL 进行编码。
您可以使用
UrlEncode
功能来实现这一点。将规则更改为:
<action type="Rewrite" url="http://localhost:8080/{UrlEncode:{R:1}}" appendQueryString="true" />
更新: 解决问题的另一种方法
<rule name="Jenkins Rewrite" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{UNENCODED_URL}" pattern="(.*)" />
<add input="{HTTP_HOST}" pattern=".*jenkins.mydomain.*" />
<add input="{HTTPS}" pattern="on" />
</conditions>
<action type="Rewrite" url="http://localhost:8080{C:1}" appendQueryString="true" />
<serverVariables>
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
<set name="HTTP_X_FORWARDED_SCHEMA" value="https" />
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
</serverVariables>
</rule>
要解决此问题,您需要在
useOriginalURLEncoding="false"
或 <globalRules>
部分中组合 <rules>
标志,并确保以未编码形式使用 URL。
下面是阻止 IIS 解码您的 URL 的工作规则示例:
<system.webServer>
<rewrite>
<globalRules useOriginalURLEncoding="true">
<rule name="TestRule">
<action type="Rewrite" url="{UNENCODED_URL}" />
</rule>
</globalRules>
</rewrite>
</system.webServer>
此外,您可能需要启用
<requestFiltering allowDoubleEscaping="true" />
来处理包含斜杠 (/)
等特殊字符的 URL。
此方法可确保 URL 按预期传递,而不会被 IIS 解码。