iisurl-rewritingreverse-proxyurl-rewrite-moduleiis-10

IIS10 URL Rewrite 2.1 double encoding issue


I have an IIS10 server with ARR 3.0 and URL Rewrite Module 2.1 that acts as a reverse proxy for several other web servers. The other servers run on different ports, so the IIS10 server provides 'friendly URLs' on port 80. URL rewriting is used to hand the request off to the back-end server.

One such server is Jenkins.

Jenkins has a warning message that tells you if the reverse proxy is well configured (more details here), and this warning message helped me find an issue in my reverse proxy.

The issue is that URL Rewrite is decoding and encoding my URLs in a way that by the time they reach Jenkins they are different from what the browser requested.

Example:

URL Rewrite Rule:

<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>

When sending the following URL:

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

I noticed that the encoded characters where being decoded before triggering the rule, making {R:1} looking like this: /administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https:/jenkins.mydomain/manage/

After some research I found out that I could use {UNENCODED_URL} instead of {R:1} to get the request string before the decoding, so I adjusted my rule action:

<action type="Rewrite" url="http://localhost:8080{UNENCODED_URL}" appendQueryString="false" />

Unfortunately the URL Rewrite is encoding the URL again after my Rewrite, making the URL received by Jenkins double encoded:

/administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%253A%252F%252Fjenkins.mydomain%252Fmanage%253F

Short summary:

When you look at this URL: /administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

What we have is: /administrativeMonitor/hudson.diagnosis.ReverseProxySetupMonitor/testForReverseProxySetup/<parameter1>

where <parameter1> = https%3A%2F%2Fjenkins.mydomain%2Fmanage%3F

The slash characters in <parameter1> are encoded so that Jenkins can know what is part of the path and what is <parameter1>.

This means that, when the URL Rewrite Decodes the URL, <parameter1> gets mixed with the rest of the path.

The desired result is getting the URL exactly as the browser sent it but pointing to the localhost:

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

Is there anyway to disable this Decoding/Encoding operations that URL Rewrite Module is doing?

PS: I found a blog post regarding URL Rewrite v2.1 features, and it says that there is a new flag that can be used to disable this behaviour, but I have no clue on how or where to set it.

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).

Does anyone here have any idea of how to do it?


Solution

  • I managed to fix the issue, by setting useOriginalURLEncoding = false described in the post I referenced in the question.

    To set the flag to go IIS Manager then select Configuration Editor and go to the section system.webServer/rewrite/rules, where you will find the useOriginalURLEncoding flag.

    Set the flag to false, and URL Rewrite will no longer encode the URLs when using the {UNENCODED_URL} variable in the rules.