IIS 7 – Enabling deny url sequences with backslash

denyiis-7redirectrequest-filteringwindows-server-2008

I've been trying to restrict backslashes \ in URL's via the Request filtering tool in IIS 7 by using:

  <configuration>
   <system.webServer>
      <security>
         <requestFiltering>
            <denyUrlSequences>
               <add sequence="\" />
            </denyUrlSequences>
         </requestFiltering>
      </security>
   </system.webServer>
</configuration>

However, the backslash rule is being completely ignored? Request filtering is definitely working as I've tried with strings instead of a backslash e.g. contact-us as a deny rule correctly sends you to a 404 page. But why is it ignoring the backslash? Is there something missing here?

Thankyou for your help

Best Answer

I looked at a similar problem recently and found that backslashes were being replaced with forward slashes by HTTP.sys before the requests were handed off to IIS. So, the Request Filtering module will never get a chance to block the request because it won't see the backslashes.

In more detail, I sent the following request

$ wget "http://www.example.com/awesome-category\awesome-products/"
--2012-08-22 12:51:31-- hhttp://www.example.com/awesome-category%5Cawesome-products/
Resolving www.example.com... 192.168.1.77
Connecting to www.example.com|192.168.1.77|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 56398 (55K) [text/html]
Saving to: `index.html'

2012-08-22 12:51:38 (6.60 MB/s) - `index.html'

And the following showed up in Wireshark:

4 0.001242000 192.168.200.42 192.168.100.177 HTTP 246 GET /awesome-category%5Cawesome-products/ HTTP/1.0

I also set up HTTP.sys event tracing to see what was happening before HTTP.sys handed the request off to IIS & .NET.

It showed the URL as being without a backslash:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
    <System>
        <Provider Name="Microsoft-Windows-HttpService" Guid="{dd5ef90a-6398-47a4-ad34-4dcecdef795f}" />
        <EventID>2</EventID>
        <Version>0</Version>
        <Level>4</Level>
        <Task>1</Task>
        <Opcode>12</Opcode>
        <Keywords>0x8000000000000002</Keywords>
        <TimeCreated SystemTime="2012-08-22T11:51:29.179726800Z" />
        <Correlation ActivityID="{80000663-0000-5d00-b63f-84710c7967bb}" />
        <Execution ProcessID="4" ThreadID="1912" ProcessorID="0" KernelTime="8820" UserTime="0" />
        <Channel>Microsoft-Windows-HttpService/Trace</Channel>
        <Computer />
    </System>
    <EventData>
        <Data Name="RequestObj">0xFFFFFA801C33B530</Data>
        <Data Name="HttpVerb">       4</Data>
        <Data Name="Url">http://www.example.com.com:80/awesome-category/awesome-products</Data>
    </EventData>
    <RenderingInfo Culture="en-GB">
        <Level>Information </Level>
        <Opcode>Parse </Opcode>
        <Keywords>
            <Keyword>Flagged on all HTTP events dealing with request processing </Keyword>
        </Keywords>
        <Task>HTTP Request Trace Task </Task>
        <Message>Parsed request (request pointer 0xFFFFFA801C33B530, method 4) with URI http://www.example.com.com:80/awesome-category/awesome-products. </Message>
        <Channel>HTTP Service Channel </Channel>
        <Provider>Microsoft-Windows-HttpService </Provider>
    </RenderingInfo>
</Event>

As far as I can tell HTTP.sys is sanitizing the backslashes in the URL by replacing them with forward slashes. This behavior was documented for IIS 6 here:

The normalization is different when directory traversal is used. For example, the following request is received:

http://www.example.com/RootTest/SubDir1\SubDir2/../../SubDir5/SubDir6

Http.sys normalizes this URL as the following URL:

http://www.example.com/RootTest/SubDir5/SubDir6

Note: The backslash is changed to a forward slash.".

It's also mentioned more recently here:

Any ‘\’ (backslashes) in a URI sent to IIS/WAS are automatically converted to a ‘/’ (forward slash). If a relative address is added that contains a ‘\’ and you send IIS a URI that uses the relative address, the backslash is converted to a forward slash and IIS cannot match it to the relative address. IIS sends out trace information that indicates that there are no matches found.

I got the same behavior on another server, so I suspect there's no way to do this with Request Filtering, in contrast to some of the documentation on iis.net. It would be great to get clearer confirmation from someone at MS, but I couldn't find anything.

Edit: Some of the above is either obsolete, incomplete, or inaccurate. See this answer for an example of rewriting a URL that contains backslashes.