简体   繁体   中英

IIS treats double-encoded forward slashes in URLs differently on the first request than it does on subsequent requests

Recently my team was asked to implement an HttpModule for an ASP.NET MVC application that handled double-encoded URLs on IIS 7 and .NET 3.5. Here's the crux of the problem:

We sometimes get URLs that have double-encoded forward slashes that look like so:

http://www.example.com/%252fbar%5cbaz/foo

There are other formats that we have to handle as well, but they all have something in common, they have a double-encoded forward slash.

To fix this, we wrote an HttpModule that only acts when a URL has a double encoded forward slash, and we redirect it to a sane URL. The details aren't important, but there are two bits that are:

  1. We can't control the fact that these URLs have double-encoded forward slashes
  2. And we have not ugpraded to .NET 4.0 yet, nor is it on the immediate horizon.

Here's the problem:

The first request after IIS starts up shows a different URL than the second request does.

If we used the URL from the above example, the first request to IIS would look like:

http://www.example.com/bar/baz/foo

and the second request would look like:

http://www.example.com/%252fbar%5cbaz/foo

This was done by inspecting the Application.Request.Url.AbsolutePath property while debugging.

Here's the smallest code example that should reproduce the problem (create a new MVC application, and register the following HttpModule):

public class ForwardSlashHttpModule : IHttpModule
{
    internal IHttpApplication Application { get; set; }

    public void Dispose()
    {
        Application = null;
    }

    public void Init(HttpApplication context)
    {
        Initialize(new HttpApplicationAdapter(context));
    }

    internal void Initialize(IHttpApplication context)
    {
        Application = context;
        context.BeginRequest += context_BeginRequest;
    }

    internal void context_BeginRequest(object sender, EventArgs e)
    {
        var url = Application.Request.Url.AbsolutePath; //<-- Problem point
        //Do stuff with Url here.
    }
}

Then, call the same URL on localhost:

http://www.example.com/%252fbar%5c/foo

NB: Make sure to insert a Debugger.Launch() call before the line in context_BeginRequest so that you'll be able to see it the first time IIS launches

When you execute the first request, you should see:

http://example.com/bar/foo

on subsequent requests, you should see:

http://example.com//bar/foo .

My question is: Is this a bug in IIS? Why does it provide different URLs when calling Application.Request.Url.AbsolutePath the first time, but not for any subsequent request?

Also: It doesn't matter whether the first request is for a double encoded URL or not, the second request will always be handled appropriately by IIS (or at least, as appropriate as handling double-encoded forward slashes can be). It's that very first request that is the problem.

Update

I tried a few different properties to see if one had different values on the first request:

First Request
 string u = Application.Request.Url.AbsoluteUri; "http://example.com/foo/baz/bar/" string x = Application.Request.Url.OriginalString; "http://example.com:80/foo/baz/bar" string y = Application.Request.RawUrl; "/%2ffo/baz/bar" bool z = Application.Request.Url.IsWellFormedOriginalString(); true 

The only interesting thing is that the Application.Request.RawUrl emits a single-encoded Forward slash ( %2f ), and translates the encoded backslash ( %5c ) to a forwardslash (although everything else does that as well).

The RawUrl is still partially encoded on the first request.

Second Request
Application.Request.ServerVariables["URL"] = /quotes/gc/v12/CMX
Application.Request.ServerVariables["CACHE_URL"] = http://example.com:80/%2ffoo/baz/bar

Interesting points from the second request:

  • IsWellFormedOriginalString() is false . On the first request it was true .
  • The RawUrl is the same (potentially helpful).
  • The AbsoluteUri is different. On the second request, it has two forward slashes.

Update

 Application.Request.ServerVariables["URL"] = /quotes/gc/v12/CMX Application.Request.ServerVariables["CACHE_URL"] = http://example.com:80/%2ffoo/baz/bar 

Open Questions

  • This seems like a bug in either IIS or .NET. Is it?
  • This only matters for the very first request made by an application after an iisreset
  • Besides using RawUrl (as we'd have to worry about a lot of other problems if we parsed the Raw Url instead of using the 'safe' URL provided by .NET), what other methods are there for us to handle this?

Keep in mind, the physical impact of this problem is low: For it to be an actual problem, the first request to the web server from a client would have to be for the above specific URL, and the chances of that happening are relatively low.

Request.Url can be decoded already - I wouldn't trust it for what you are doing.

See the internal details at: Querystring with url-encoded ampersand prematurely decoded within Request.Url

The solution is to access the values directly via Request.RawUrl.

I realize your prob is with the path, but it seems the same thing is going on. Try the RawUrl - see if it works for you instead.

This really isn't an answer, but possibly a step in the right direction. I haven't had time to create a test harness to prove anything.

I followed this.PrivateAbsolutePath through Reflector and it goes on and on. There is a lot of string manipulation when it's accessed.

public string AbsolutePath
{
    get
    {
        if (this.IsNotAbsoluteUri)
        {
            throw new InvalidOperationException(SR.GetString("net_uri_NotAbsolute"));
        }
        string privateAbsolutePath = this.PrivateAbsolutePath; //HERE
        if (this.IsDosPath && (privateAbsolutePath[0] == '/'))
        {
            privateAbsolutePath = privateAbsolutePath.Substring(1); 
        }
        return privateAbsolutePath;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM