IIS在第一个请求中对URL中的双重编码正斜杠的处理方式与后续请求的处理方式不同

Geo*_*ker 7 .net c# iis asp.net-mvc httpmodule

最近,我的团队被要求为ASP.NET MVC应用程序实现一个HttpModule,该应用程序处理IIS 7和.NET 3.5上的双重编码URL.这是问题的症结所在:

我们有时会得到具有双重编码正斜杠的URL,如下所示:

http://www.example.com/%252fbar%5cbaz/foo
Run Code Online (Sandbox Code Playgroud)

还有其他格式我们必须处理,但它们都有一些共同点,它们有一个双重编码的正斜杠.

为了解决这个问题,我们编写了一个HttpModule,它仅在URL具有双重编码的正斜杠时起作用,并且我们将其重定向到一个合理的URL.细节并不重要,但有两个位:

  1. 我们无法控制这些URL具有双重编码正斜杠的事实
  2. 我们还没有对.NET 4.0进行过分析,也没有立即展望.

这是问题所在:

IIS启动后的第一个请求显示的URL与第二个请求不同.

如果我们使用上面示例中的URL,则对IIS的第一个请求如下所示:

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

第二个请求看起来像:

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

这是通过Application.Request.Url.AbsolutePath在调试时检查属性来完成的.

这是应该重现问题的最小代码示例(创建一个新的MVC应用程序,并注册以下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.
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在localhost上调用相同的URL:

http://www.example.com/%252fbar%5c/foo
Run Code Online (Sandbox Code Playgroud)

注意:确保Debugger.Launch()在该行之前插入一个呼叫,context_BeginRequest这样您就可以在IIS首次启动时看到它

当您执行第一个请求时,您应该看到:

http://example.com/bar/foo

在后续请求中,您应该看到:

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

我的问题是:这是IIS中的错误吗?为什么它Application.Request.Url.AbsolutePath在第一次调用时提供不同的URL ,而不是任何后续请求?

另外:第一个请求是否是双重编码的URL并不重要,第二个请求将始终由IIS适当处理(或者至少适当处理双重编码的正斜杠).这是问题的第一个请求.

更新

我尝试了几个不同的属性,看看第一个请求是否有不同的值:

第一次请求
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
Run Code Online (Sandbox Code Playgroud)

唯一有趣的是Application.Request.RawUrl发出一个单编码的正斜杠(%2f),并将编码的反斜杠(%5c)转换为一个前向闪光(尽管其他一切都是这样).

RawUrl仍然是部分编码的第一请求.

第二个请求
string u = Application.Request.Url.AbsoluteUri;
"http://example.com//foo/baz/bar"
string x = Application.Request.Url.OriginalString;
"http://example.com:80/%2ffoo/baz/bar"
string y = Application.Request.RawUrl;
"/%2ffoo/baz/bar"
bool z = Application.Request.Url.IsWellFormedOriginalString();
false
Run Code Online (Sandbox Code Playgroud)

第二个请求的有趣点:

  • IsWellFormedOriginalString()false.在第一次请求时true.
  • RawUrl是相同的(可能有用).
  • AbsoluteUri不同的是.在第二个请求中,它有两个正斜杠.

更新

Application.Request.ServerVariables["URL"] = /quotes/gc/v12/CMX
Application.Request.ServerVariables["CACHE_URL"] = http://example.com:80/%2ffoo/baz/bar
Run Code Online (Sandbox Code Playgroud)

打开问题

  • 这似乎是IIS或.NET中的错误.是吗?
  • 这仅适用于应用程序之后的第一个请求iisreset
  • 除了使用RawUrl之外(如果我们解析Raw Url而不是使用.NET提供的'安全'URL)我们还要担心很多其他问题,还有什么其他方法可以解决这个问题?

请记住,此问题的物理影响很小:因为它是一个实际问题,从客户端向Web服务器的第一个请求必须是针对上述特定URL,并且发生这种情况的可能性相对较低.

ric*_*ott 0

这确实不是一个答案,但可能是朝着正确方向迈出的一步。我没有时间创建测试工具来证明任何事情。

我跟踪this.PrivateAbsolutePath了 Reflector,它一直在继续。访问时有很多字符串操作。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)