我有一個使用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