Share via


ASP.NET File Upload: How to prevent network clogging

Denial of service is one of the threats that you need to consider while implementing file upload functionality in your web application. If a user uploads a huge file, it will clog the network and consume server’s memory.

Let us look at what happens under the hood when a file is uploaded. When a form with an “input type=file” element is submitted, the entire file is posted to the server as a HTTP POST request.

Internally the browser opens up a TCP connection with the server on port 80 to send the posted data. After establishing the TCP connection, the client begins to transfer the data. There is a limit to the data (usually 64KB) that the transport layer on the client can transfer to the server without receiving an acknowledgement from the transport layer on the server. The transport layer on the server buffers this received data and transfers it to the application which is listening on port 80, which in this case is IIS. After transferring it to the application layer (IIS in this case), the transport layer sends an acknowledgement to the client’s transport layer, which can then send more data.

IIS, as it receives this data, checks the extension of the POST request. Since it is .aspx and since .aspx extension maps to the aspnet_isapi dll, IIS passes on the request to this dll. This aspnet_isapi dll continues to read data from the TCP connection, and as a chunk of data is read, passes it to the ASP.NET engine using named pipes.

The first thing that the ASP.NET engine does is to compare the “Content Length” header which is a part of the HTTP request (underlined in the picture), with the MaxRequestLength attribute in the <httpruntime> setting. If the content length is greater, it immediately throws the “Max Request Length exceeded” exception. Note that when the ASP.NET engine reads the header, a part of the request is still being transferred on the network.

As soon as the ISAPI dll gets notification of this exception, it closes the TCP connection with the client. No more data is transferred on the network for this request. This is why the MaxRequestLength attribute in the <httpruntime> section is the correct method of restricting file size in ASP.NET, and it restricts both network clogging and excessive server memory usage.

The below table shows actual bytes transferred from the client to the server (recorded using a network protocol analyzer) by varying the upload file size.

Uploaded file size (KB)

MaxRequestLength (KB)

Bytes actually transferred on network (KB)

800

1000

800

1100

1000

127

2000

1000

127

12000

1000

127

30000

1000

127

Summary: If a file with size more than the MaxRequestLength setting is uploaded, the actual bytes transferred on the network is only about 120-150KB. By this time, the ASP.NET engine reads the content length header, knows that the incoming request is too large and throws an exception which causes the TCP connection to close. So using <httpruntime MaxRequestLength=value> is how you can prevent network clogging and excessive use of server memory while implementing a file upload functionality.

References:-

https://www.ietf.org/rfc/rfc1867.txt

https://support.microsoft.com/kb/295626

https://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/regentry/58813.mspx?mfr=true

Varun Sharma

Security Engineer

Microsoft – ACE Team

varun dot sharma at microsoft dot com

Comments

  • Anonymous
    September 19, 2007
    PingBack from http://msdnrss.thecoderblogs.com/2007/09/19/aspnet-file-upload-how-to-prevent-network-clogging/
  • Anonymous
    September 20, 2007
    Hi,what happens if I fake the Content-Length header? How is the behaviour of the IIS/ASP.NET then?So I upload 30.000 KBytes and set the content-length to 1024KB?
  • Anonymous
    September 20, 2007
    That is a very good question!The “Content Length” header, like any other HTTP header, can be controlled by the client. But ASP.NET would only read as much of the request into its buffer as specified in the “Content Length” header. So changing it doesn’t defeat the ASP.NET engine.If you specify 1024 KB in the "Content Length" header, but the actual data is 30MB, the maximum buffer size allocated to this request by ASP.NET will be 1024KB (+/- 64KB). Once that much of data is read, the TCP connection will be closed. No more data will be transferred on the network.I tried to reproduce the same scenario. I set the MaxRequestLength to 2MB. Then I uploaded a file of 30MB. Using a HTTP debugger tool on the client, changed the "Content Length" to 1024KB. The total bytes transferred on the network was 1030KB.Hope that answers your question!Regards,Varun
  • Anonymous
    October 05, 2007
    The comment has been removed
  • Anonymous
    October 05, 2007
    The comment has been removed