我有一个使用WebForms的ASP.NET 3.5应用程序,目前它正在IIS6上承载。一切都很好。ASP.NET在切换到IIS8后连接断开时处理请求
但是,在切换到安装了IIS8的Windows 2012服务器后,我们会间歇性地收到截断的请求。大多数情况下,这会在我们的事件日志中显示一个视图状态异常,但是,在没有ViewState的表单上,我们会收到不完整的帖子(最后几个字段丢失/部分截断)。
这成为那么多问题,我们升级到微软的支持,和调试星期后,他们说这是II7和上面的“正确”的行为。他们的解释是,从6 IIS管道7
IIS6的变化,下面将其传递到Asp.net之前将缓冲整个请求,截断请求将被忽略。
IIS7及以上版本会在发送初始头文件后将请求发送到Asp.net,这将由应用程序处理截断的请求。
时要么有连接问题(用户tranmission期间拔掉他们的有线电视)或一个职位期间,当用户按下停止/重新加载页面后,此成为问题。
在我们的HTTP日志中,我们看到与截断的请求相关的“connection_dropped”消息。
我无法相信,这种行为是有意的,但我们有一些不同的服务器上进行测试,并得到与IIS7和上面相同的结果(Windows 2008中,2008 R2,和2012年)。
我的问题是:
1)请问这种行为甚至有意义吗? 2)如果这是“正确的”行为,你如何保护你的应用程序免受潜在处理不完整的数据?
3)为什么应用程序开发人员有责任检测不完整的请求?假设,为什么应用程序开发人员会处理不完整的请求,而忽略它?
更新
我写了一个小型的asp.net应用程序和网站来演示这个问题。
服务器
Handler.ashx.cs
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod == "POST")
{
var lengthString = context.Request.Form["Length"];
var data = context.Request.Form["Data"];
if (lengthString == null)
{
throw new Exception("Missing field: Length");
}
if (data == null)
{
throw new Exception("Missing field: Data");
}
var expectedLength = int.Parse(lengthString);
if (data.Length != expectedLength)
{
throw new Exception(string.Format("Length expected: {0}, actual: {1}, difference: {2}", expectedLength, data.Length, expectedLength - data.Length));
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World, Request.HttpMethod=" + context.Request.HttpMethod);
}
public bool IsReusable
{
get { return false; }
}
}
客户
的Program.cs
static void Main(string[] args)
{
var uri = new Uri("http://localhost/TestSite/Handler.ashx");
var data = new string('a', 1024*1024); // 1mb
var payload = Encoding.UTF8.GetBytes(string.Format("Length={0}&Data={1}", data.length, data));
// send request truncated by 256 bytes
// my assumption here is that the Handler.ashx should not try and handle such a request
Post(uri, payload, 256);
}
private static void Post(Uri uri, byte[] payload, int bytesToTruncate)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
// this allows us to disconnect unexpectedly
LingerState = new LingerOption(true, 0)
};
socket.Connect(uri.Host, uri.Port);
SendRequest(socket, uri, payload, bytesToTruncate);
socket.Close();
}
private static void SendRequest(Socket socket, Uri uri, byte[] payload, int bytesToTruncate)
{
var headers = CreateHeaders(uri, payload.Length);
SendHeaders(socket, headers);
SendBody(socket, payload, Math.Max(payload.Length - bytesToTruncate, 0));
}
private static string CreateHeaders(Uri uri, int contentLength)
{
var headers = new StringBuilder();
headers.AppendLine(string.Format("POST {0} HTTP/1.1", uri.PathAndQuery));
headers.AppendLine(string.Format("Host: {0}", uri.Host));
headers.AppendLine("Content-Type: application/x-www-form-urlencoded");
headers.AppendLine("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/99.0");
headers.AppendLine("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers.AppendLine("Connection: Close");
headers.AppendLine(string.Format("Content-Length: {0}", contentLength));
return headers.ToString();
}
private static void SendHeaders(Socket socket, string headers)
{
socket.Send(Encoding.ASCII.GetBytes(headers));
socket.Send(Encoding.ASCII.GetBytes("\n"));
}
private static void SendBody(Socket socket, byte[] payload, int numBytesToSend)
{
socket.Send(payload, 0, numBytesToSend, SocketFlags.None);
}
当用户在浏览器上按下停止按钮时,可能会出现此问题。无论我处于集成还是经典模式都无关紧要。至于你的第二点,这看起来像是框架应该保护你的东西,asp.net应该是HTTP之上的抽象。虽然这绝对是一个抽象的漏洞,但我觉得这是我不应该写的一个问题。写这个问题非常困难。我将用测试程序更新原始问题以证明问题。 – Matthew
测试程序可能是最好的。与此同时,是的,我可以理解你对预测这种低杠杆错误感到沮丧,但正如你所说,这是一个漏洞抽象和漏洞抽象只能保护你不受这么多。 FWIW,我从来没有见过这种情况发生在4.0或4.5。 – gfish3000
我更新了原始问题的复制 – Matthew