IIS10 URL 重写 2.1 双重编码问题

IIS10 URL Rewrite 2.1 double encoding issue

我有一个带有 ARR 3.0 和 URL 重写模块 2.1 的 IIS10 服务器,它充当其他几个 Web 服务器的反向代理。其他服务器运行在不同的端口,所以IIS10服务器在80端口提供'friendly URLs'。URL重写用于将请求交给后端服务器。

一个这样的服务器是Jenkins

Jenkins 有一条警告消息告诉您反向代理是否配置正确 (more details here),这条警告消息帮助我找到了我的反向代理中的问题。

问题是 URL Rewrite 正在解码和编码我的 URLs,当它们到达 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>

发送时URL:

https://jenkins.mydomain/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

我注意到编码字符在触发规则之前被解码,使 {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

简短摘要:

当你看到这个时 URL: /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,但指向本地主机:

http://localhost:8080/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

是否可以禁用 URL 重写模块正在执行的 Decoding/Encoding 操作?

PS:我发现了一个关于 URL Rewrite v2.1 特性的 blog post,它说有一个新的标志可以用来禁用这个行为,但是我不知道如何或在哪里设置它。

In URL Rewrite versions prior to v7.1.1980, when one tries to use UNENCODED_URL, URL Rewrite will encode it which may lead to double encoding if the original URL was already encoded This is in violation of section 2.4 of RFC3986, which says "Implementations must not percent-encode or decode the same string more than once, as decoding an already decoded string might lead to misinterpreting a percent data octet as the beginning of a percent-encoding, or vice versa in the case of percent-encoding an already percent-encoded string." It also made the use of UNENCODED_URL impractical, especially in reverse forwarder scenarios with ARR where the backend servers expect the URL to be passed unmodified.

In v7.1.1980, we are adding a feature flag, useOriginalURLEncoding that allows you to turn off this non-compliant URL Encoding when set to true. The default behavior will remain unchanged (useOriginalURLEncoding is true by default).

这里有人知道怎么做吗?

您可以使用 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>

我通过设置我在问题中引用的 post 中描述的 useOriginalURLEncoding = false 设法解决了这个问题。

要设置标志,请转到 IIS Manager 然后 select Configuration Editor 并转到 system.webServer/rewrite/rules 部分,您将在其中找到 useOriginalURLEncoding 标志。

将标志设置为 false,当在规则中使用 {UNENCODED_URL} 变量时,URL Rewrite 将不再对 URL 进行编码。