Friday, October 31, 2008

Security Considerations for File Upload

Security Considerations for File Upload:

Web applications are all about communicating with an end-user to abstract what information you need to from them depending on the service offered and responding with the data required. In many cases with Web application pages, it is usually simply textual data that is collected and stored. However, there are many cases where web applications need more than simple textual data; your web application may require file upload functionality to upload files to the server by users. Well, with Asp.Net 1.x or greater version it is become so easy to upload files to the server.

Back in the ASP world, uploading files via a web page was a difficult task. The problem was that due to the encryption type of the form used to submit the file from the client's browser. With the release of ASP.NET 1.x, it seemed that all our problems had been solved. ASP.NET 1.x made dealing with uploads much simpler then it had ever been in the past, but there were still a few loose ends like setting the form "enctype" property to "multipart/form-data" and there was no Web Control to handle the UI for you. But, with the release of ASP.NET 2.0 and the inclusion of the new FileUpload control that those loose ends would finally be tied up.
Well, now uploading files to the server become easy but still you need to consider security issues while uploading the files to the server. We will discuss the guidelines for secure file upload in this article.

Before discussing the security considerations for file upload it is better to have a look how the files can be uploaded to the server in ASP.NET.

<html>
<head></head>
<body>
<form runat="server" enctype="multipart/form-data">
/* HTML input control that is used to upload file has a simple type of file */
Select a file to upload : <input type="file" id="myFile" runat="Server">
<p> <input type="submit" id="Upload" runat="Server” value="Upload File"
OnServerClick="Upload_Click"></p>
</form>
</body>
</html>

void Upload_Click(Object sender, EventArgs e) {
/* Get a reference to PostedFile object */
System.Web.HttpPostedFile uploadedFile = myFile.PostedFile;

if (uploadedFile != null) {
try {
/* Get size of uploaded file */
int fileLen = uploadedFile.ContentLength;
/* Allocate a buffer for reading of the file */
byte[] fileData = new byte[fileLen];
/* Read file data from the Stream */
uploadedFile.InputStream.Read(fileData, 0, fileLen);
/* Create a file * /
FileStream fs = new FileStream(uploadedFile.FileName, FileMode.Create);
/* Just we are writing to the current folder. If you want to other folder just append the path. Now write the data to the File */
fs.Write(fileData, 0, fileData.Length);
/* Close file */
fs.Close();

/* Or simply you can save the file to the disk with the following statement
myFile.PostedFile.SaveAs("D:\\MyFolder\\" + myFile.PostedFile.FileName); */
}
catch (Exception ex)
{
/* Log the exception */
}
}


Well, now we discuss the security considerations for file upload.

Guidelines for secure file upload:

  • Upload all files to a file-share and not directly to database as a blob.

    If the files are uploaded to the database as a blob then the data that resides on the file will not be validated thus may lead to injection attacks. For example an attacker may use this vulnerability to inject malicious data in to the database and use it later to perform other attacks. So, it is always a better way to upload the files to a file-share instead of the database as a blob.

  • In general, try to store client-supplied files on their own partition. Avoid storing them on the same partition as the web site, and always avoid storing them on the system drive.

    An attacker might be able to exhaust free space on the system drive or the web site drive, resulting in unexpected behavior by the OS or the web site.
    Alternately, if the attacker can do a directory-traversal attack, then the attacker might be able to replace system or web site files, thereby compromising the web server system.
    Allowing a user to upload the files either to a system drive or website partition may lead to DOS attacks.

  • If client-supplied files are stored on the web site partition, make sure that they never reside within the web site directory tree.

    Allowing client-supplied files in the web site directory tree might result in an attacker being able to upload a malicious .asp file, and then navigate to it using an HTTP GET request. This would cause the server to execute the attacker-supplied page using the identity of the web application account.
    Alternately, an attacker might upload a file containing malicious script, and then lure a victim user to access the same file via GET, effectively resulting in a cross-site script exploit.

  • The HTTP POST method is preferable to the HTTP PUT method.

    When using the PUT method, you need to take extra care to ensure that user-supplied files cannot be accessed with other methods such as GET.
    This would result in the same cross-site script attack described above.

  • Scan client-supplied files for viruses using a well known industry standard virus scanner.

    Allowing client-supplied files to be uploaded to a server without a virus scan might result in an attacker being able to upload malicious files such as viruses.
    Make sure that the well known industry standard virus scanner is used on the server and the virus signatures are up to date.
    Ensure all incoming/outgoing Files are scanned and they are scanned on real time basis.
    Never assume that files which pass a virus scan are completely safe, they may contain a malicious code that could help the attacker to perform other attacks like code injection.

  • Check and restrict the size of uploaded files if possible, and allocate server-side resources sparingly.

    Attackers who can upload extremely large files can potentially deplete or exhaust server resources, resulting in unexpected behavior by the server or web site.
    Ensure application checks for the length so that it doesn’t potentially deplete or exhaust server resources.

  • When storing client-supplied files on disk, generate your own file paths and file names. Do not allow user-supplied data to influence the path or name of the file as it is actually stored on disk.

    By depriving attackers of the ability to influence how your application performs file-level I/O, you all but eliminate a number of possible attacks, such as directory traversal, induced filename collisions, and more.
    If it is necessary to store the file on disk using a user-supplied name, you should do the following:
    a. Use the Path.GetFilename() method to safely retrieve a valid filename from the client-supplied value.
    b. Use a directory path you choose yourself, without allowing user input to influence the directory path.

  • Lock down access to specific users and security-groups requiring access to the upload share.

    Upload share directory should be properly ACL’ed.

  • Treat client-supplied files like any other element of user input and validate, validate, validate.

    Verify that the file is of the type the user is permitted to upload.
    Discard any file which does not have an extension or name that is explicitly allowed or expected by your application.
    Also consider inspecting the internal contents of the file to ensure that it is of the type advertised by the user-supplied name or extension.

Some useful references:

ASP.NET File Upload: How to prevent network clogging:
http://blogs.msdn.com/ace_team/archive/2007/09/19/asp-net-file-upload-how-to-prevent-network-clogging.aspx
File Uploading in ASP.NET 2.0:
http://www.15seconds.com/issue/061116.htm
Uploading Files Using the File Field Control:
http://msdn.microsoft.com/en-us/library/aa478971.aspx
File Upload with ASP.NET:
http://www.codeproject.com/KB/aspnet/fileupload.aspx