Enforce HTTPS in IIS without using cache unsafe server variables - iis

I'm currently using the following rule to enforce https on a site:
<rule name="Enforce HTTPS" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" ignoreCase="true" pattern="^off$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
The problem is that the HTTPS server variable that I'm using in the condition is not part of the list of server variables that "do not cause any effect on output caching policy" (see full list).
The reason why this is a problem is that after setting up some Failed Request Tracing Rules, I realized that some entries have the following warning : REWRITE_DISABLED_KERNEL_CACHE
After some research, I found a related forum thread mentioning that:
The URL Rewrite Module will disable kernel mode cache if any rule in a
rule set had a condition that used cache unsafe server variable. The
cache was disabled regardless whether the requested URL matched the
rule pattern or not.
This wouldn't be a problem if performance wasn't an issue, but the site isn't that fast and I'm wondering if this cache problem couldn't be part of the issue.
From reading the list of safe variables, it seems like there is none that will contain the protocol used for the request, so this doesn't seem possible, but I still thought I might ask just in case.

Had the same issue and solved this by routing the HTTP traffic into a separate IIS application that contains nothing more than a single web.config file that routes the traffic into the HTTPS application. So the web.config file in the HTTPS application is free of any unsafe variables.

We can bypass the HTTP protocol to access the website using HTTPS, and then use the IIS log to view the visit records of the website, where each record contains the time consumption of the visit.
Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs-
version cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2020-04-15 02:50:57 fe80::a4fe:6d79:f2b8:d031%6 GET / - 446 -
fe80::a4fe:6d79:f2b8:d031%6 HTTP/2 Mozilla/5.0+
(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+
(KHTML,+like+Gecko)+Chrome/80.0.3987.163+Safari/537.36
- 403 14 0 2158
The last field indicates the time-taken in one request.
I don’t think IIS output cache will have a significant impact on IIS website access performance when only checking the HTTPS server variable and redirect the URI.

Related

Windows IIS ARR Reverse Proxy Encoding Issue

We have an environment with an Windows 2019 Server IIS 10, which is acting as Reverse Proxy (ARR) for my IIS Server farm (Application Request Routing 3.0 and URL Rewrite 2.1). We send the users name in the HTTP headers. But my ARR somehow screws up the encoding (we are using german special characters, e.g. ö,ü,ß...), so when i check the respone of the WebServer it shows me: H%C3%B6lmuth M%C3%A4%C3%9Fterm%C3%BCller instead of Hölmuth Mäßtermüller.
I have an old environment with Windows 2012R2 Server with the same configuration, in this environment the display of the name is correct. I have checked all kind of settings between old and new servers, but cannot find any difference.
Futher i have used Failed Request Loggins and Network Monitor to see what the server receives and sends, below find the results.
Received Request on the IIS ARR (old and new):
X-AUTHENTICATE-FamilyName: M%C3%A4%C3%9Fterm%C3%Bcller
X-AUTHENTICATE-GivenName: H%C3%83%C2%B6lmuth
X-AUTHENTICATE-cn: H%C3%B6lmuth M%C3%A4%C3%9Fterm%C3%BCller
Request send to the IIS (new):
X-AUTHENTICATE-FamilyName: M%C3%A4%C3%9Fterm%C3%BCller
X-AUTHENTICATE-GivenName: H%C3%83%C2%B6lmuth
X-AUTHENTICATE-cn: H%C3%B6lmuth M%C3%A4%C3%9Fterm%C3%BCller
Request send to the IIS (old):
X-AUTHENTICATE-FamilyName: Mäßtermüller
X-AUTHENTICATE-GivenName: Hölmuth
X-AUTHENTICATE-cn: Hölmuth Mäßtermüller
Anyone has an idea how i can change this behaviour? Help would be much appreciated.
Can you give me an example how to use the {UNENCODED_URL} variable. Currently we are using the rewrite module to route requests to specific Server Farms, see my rules below:
<rewrite>
<globalRules useOriginalURLEncoding="true">
<rule name="ARR_BPBP-DEV_loadbalance" patternSyntax="Wildcard" stopProcessing="true">
<match url="*" />
<action type="Rewrite" url="http://BPBP-DEV/{R:0}" />
<conditions>
<add input="{HTTP_HOST}" pattern="bmi-bpbp-dev.vecos.at" />
</conditions>
</rule>
<rule name="ARR_BPBP-TEST_loadbalance" patternSyntax="Wildcard" stopProcessing="true">
<match url="*" />
<action type="Rewrite" url="http://BPBP-TEST/{R:0}" />
<conditions>
<add input="{HTTP_HOST}" pattern="bmi-bpbp-test.vecos.at" />
</conditions>
<serverVariables>
</serverVariables>
</rule>
</globalRules>
How can i adapt the rules to use the {UNENCODED_URL} variable?
When an HTTP request arrives on Windows, the latest HTTP.sys encodes both URL and HTTP headers, and puts the original URL in UNENCODED_URL server variable so that it can be recovered afterwards.
However, the original headers (such as X-AUTHENTICATE-FamilyName: Mäßtermüller) do not seem to be preserved (no clear documentation on that), so there isn't any easy way to recover them.
If you want to modify the the header from X-AUTHENTICATE-FamilyName: M%C3%A4%C3%9Fterm%C3%BCller back to X-AUTHENTICATE-FamilyName: Mäßtermüller, the only way I can think of is to write a custom IIS module to perform the decoding step.
Alternatively, you might modify your other code to accept such encoded header values (and decode them when needed in your code), as anyway that's how Windows/IIS behaves now and you cannot fight it.
Try to set the useOriginalURLEncoding to false, and URL rewrite will no longer encode the urls when using the {UNENCODED_URL} variable in the rules.
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.

how to create multiple custom 503 pages in IIS

A Temporary down page (e.g. updating your servers SW) should ideally have a response code of 503, but you could get away with 307, but in no case should it be 200 (as google will index this and it will affect your SEO)
In IIS rewrite rules, you have 3 options for implementing a redirect to a down page, rewrite, redirect and customResponse:
<action type="Rewrite" url="/site1.html" />
<action type="Redirect" url="/site1.html" redirectType="Temporary" />
<action type="CustomResponse" statusCode="503" subStatusCode="0" statusReason="Site Unavailable" statusDescription="Down for maintenance" />
The problem is if you want a 503 response, you cant redirect to the required page.
We have 3 websites for different brands using episerver CMS.
When we do maintenance, or just want to take a site down, we have a single azure web app (aka iis) which has 3 holding pages, one for each.
so our site down website has 3 pages:
/site1.html
/site2.html
/site3.html
We use Azure traffic manager to point to the live site or the site down page, and we currently have redirects which work, but incorrectly give 200 response:
<rewrite>
<rules>
<rule name="site1" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="mysite" />
</conditions>
<action type="Rewrite" url="/site1.html" />
</rule>
<rule name="site2" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="myothersite" />
</conditions>
<action type="Rewrite" url="/site2.html" />
</rule>
etc.
</rules>
</rewrite>
In order to fix this issue (offer a different site down page per site, and respond with 503), what are the options?
I would guess its possible to setup something like 3 different named virtual hosts, each with nothing except a custom 503 error page + a catch all CustomResponse action? Any examples of such a config?
To be clear, our app may well be running normally, but we may want to use our traffic manager to point the public at a "down" page which has a 503 respose during maintenance. The website sorving the down page has nothing to do with the website serving the site/applicaion itself.
Sadly, as the Microsoft document describes – there is no way to customize the 503 HTTP error.
Even use rewrite to make it display custom 503 page, In fact the request get into IIS and rewrite successful, then response to client. The whole process is perfect and your web service doesn’t stop.
The error is detected by the IIS server as it attempts to hand the incoming request to application. Everything application does is performed in its app pool. Modules like rewrite and custom error page are all executed in this way. 503 handled by the http.sys you cannot create a custom error page at all, as it is processed before it gets to iis. Therefore, both hope that the web server will stop reporting 503, but also hope that the server can process the request to display the page you defined. These two conflicts.
If your application is asp.net, there’s another way to custom 503. You can place a text file named "app_offline.htm" in the root of the site, all requests to that website will redirect to that app_offline.htm file. Basically, if you need to take an entire ASP.NET site offline, you can place some nice message in that file. Then, any new requests to a URL, any URL, in that website will redirect to that file allowing you to do maintenance to the site, upgrades, or whatever. It is not really a redirect though. ASP.NET essentially shuts down the site, unloads it from the server, and stops processing any requests to that site. That is, until you delete the app_offline.htm file - then things will continue as normal and your ASP.NET site will load up and start serving requests again.

IIS URL Rewrite behaves differently for HTTP vs HTTPS

I've been trying to use the URL Rewrite module to create a rule that looks for any set of two or more forward-slashes in the URL (past the first set) that will redirect the browser to a URL with all sets of multiple forward slashes replaced with just one. Example:
http://myhost.com/abc//def//ghi//jkl//iisstart.png
should redirect to
http://myhost.com/abc/def/ghi/jkl/iisstart.png
I already understand that IIS sees these two URLs as functionally equivalent, but for this public-facing site we want to avoid any chance that crawlers will index URLs with the multiple forward slashes; hence the redirection. So here's the rule I put together:
<rule name="Redirect URLs with Multiple Forward Slashes" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<action type="Redirect" url="{URL}" appendQueryString="true" />
<conditions logicalGrouping="MatchAny">
<add input="{UNENCODED_URL}" pattern="//" />
</conditions>
</rule>
I tested this on my local box, and it produced the expected outcome (the redirection). I copied it into a web.config on a development server and tried it out, but it didn't work. I even took the path of making sure the URL Rewrite installation matched the version on the development server (it's 2.0, and upgrading would be a pain in our large production server farm so I'd like to avoid that). After that, I took into account that our development server, by design, only serves up HTTPS, while I'd been testing in HTTP on my local box. When I enabled HTTPS on my local box, the rewrite rule didn't work with an HTTPS URL but worked fine with an HTTP URL pointing to the same resource.
All the URL Rewrite documentation I've looked at makes reference to HTTP, and there are no references to HTTPS. What am I doing wrong here?
For the record - my local box is running Windows 10, and has IIS version 10. The dev server is running Server 2012, and has IIS version 7.5.

Redirect to FQDN in IIS Not Working

None of the answers I've found to questions like this (notably this one) work for me, so here I go.
We are running IIS 8 on Windows Server 2012 R2. We have a wildcard certificate (*.mydomain.com) installed on the server. On the Default Web Site we have a single binding to accept incoming https requests on port 443. I have a second Web Site set with a single binding to accept incoming http requests on port 80.
On the latter Web Site I've created a URL Rewrite rule to redirect all incoming non-HTTP traffic to https://myserver.mydomain.com{REQUEST_URI}, and this works perfectly. If I browse to either http://myserver.mydomain.com/homepage or http://myserver/homepage, I am sucessfully redirected to the HTTPS version of the site with the full domain name included and thus it loads just fine.
If I browse to https://myserver.mydomain.com/homepage, the site also loads perfectly.
However, I am trying to create another URL Rewrite rule on the Default Web Site so that requests to https://myserver/homepage (Note: HTTPS but the full domain name is omitted) are redirected to the https://myserver.mydomain.com/homepage. The reason for this is that the SSL certificate is only matched if the full domain is included. As it stands, if I enter https://myserver/homepage I get a security warning (NET::ERR_CERT_COMMON_NAME_INVALID).
I've created the rule which I think should work, based on the answer I linked to above, but it doesn't work and I don't know why. My rule look like this:
<rewrite>
<rules>
<rule name="Redirect to FQDN" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^myserver$" />
<add input="{HTTPS}" pattern="^ON$" />
</conditions>
<action type="Rewrite" url="https://myserver.mydomain.com/{R:1}" />
</rule>
</rules>
</rewrite>
Even with this rule in place and enabled, when I browse to https://myserver/homepage I get the security message. What am I doing wrong with this rule?
Problem is that you have SSL only for *.mydomain.com. And when you accessing https://myserver it will return certificate error because your cert is not valid for this domain.
For better understanding about steps during SSL connection:
In your case, the problem is between step 2 and 3

Redirect Subdomain URL to another SubDomain in IIS

I need to redirect a "fake" sub domain to a real subdomain in IIS 7.5. The reason is that the marketing department doesn't want to use the actual website address in print pieces.
Actual site URL:
reporting.usapartners.com
Marketing dept wants
report.usapartners.com (fake) to redirect to reporting.usapartners.com (real)
Again, report.usapartners.com does not exist, only reporting.usapartners.com exists
Here is what I tried
I added a binding in IIS, for the site reporting.usapartners.com. I added report.usapartners.com as the host name and used the reporting.usapartners.com IP address
Then I went into reporting.usapartners.com web.config and added this:
<rewrite>
<rules>
<rule name="report" stopProcessing="true">
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="report.usapartners.com" negate="false" />
</conditions>
<action type="Redirect" url="http://reporting.usapartners.com" appendQueryString="false" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
Looks like my solution creates an alias that cannot be redirected to.
Am I even approaching this problem correctly? Seems like it should be a simple problem to solve but perhaps not? Any ideas are welcomed and appreciated.
Thanks
I think you need to create a separate site with host bindings for report.usapartners.com (the fake site) in IIS. This is going to be a stub site (it will still need a path on the disk, but it's only going to have a web.config in there) which will just host a redirect rule.
Now click on HTTP Redirect for that site in IIS and tick Redirect requests to this destination and put http://reporting.usapartners.com in the textbox. Then tick Redirect all requests to exact destination (instead of relative to destination), don’t tick the next one and then choose Status Code Permanent (301).
If you want it to redirect and keep the subdirectories and/or query string, then you can change the contents of the textbox to be http://reporting.usapartners.com$S$Q. Note that there is no trailing slash in this case. The $S preserves the sub directories and the $Q preserves the query string.
Your rule is causing a redirect loop.
Observe what your rule does:
Match any given URL (this includes "/", "/something", "/something/another.html", etc.)
If the host name ISN'T "report.usapartners.com"
Redirect permanently the request to "http://reporting.usapartners.com"
So, as you see, as soon as the user is redirected to the reporting subdomain, it gets redirected again to reporting, because hostname isn't "report.usapartners.com".
The key here is the negate="true" attribute on the rule condition. Remove it or set it to false and you are good to go.
Edit:
You are almost there.
The real solution would be to change the host name on the rule to the desired host, keeping the negate true, so your rule would do:
Match any given URL (this includes "/", "/something", "/something/another.html", etc.)
If the host name ISN'T "reporting.usapartners.com"
Redirect permanently the request to "http://reporting.usapartners.com"
Code:
...
<add input="{HTTP_HOST}" pattern="reporting.usapartners.com" negate="true" />
...

Resources