s
Contact Login Register
h M

Secure Programming Tips - Handling File Uploads

Week 6: Handling File Uploads

Author: Chad Nash/Thursday, October 10, 2013/Categories: SQL Performance / Code Security

Rate this article:
No rating

Week 6: Handling File Uploads


Online photo albums, document repositories, content management systems, all of these applications have one thing in common, they generally allow a user to upload files to a remote server. A server, that in most cases, hosts numerous other applications. A server that may store extremely sensitive customer information. A server, that if compromised, could result in the theft of customer records, confidential corporate information, or potentially compromise the entire corporate network. It's true, even the simplest thing of letting a user upload an image to your server, could result in the complete compromise of your entire corporate network. When's the last time you performed proper security testing on your upload functionality?

When allowing user's to upload files to your server, there are several areas we must pay particular attention to. These areas include proper input validation of valid file types, the location the uploaded files will be stored and the various permissions associated with the file storage. A simple mistake in anyone or all of these areas can result in a catastrophic compromise of your server. So it is absolutely essential when allowing a user to upload files to your server, you put your best security foot forward and enforce strict rules associated with this functionality.

Generally, when we allow a user to upload a file to our server we put a restriction on the acceptable file types we will allow them to upload. In some cases we may allow image files, such as .jpg, .gif, .png, etc. Whereas in other cases, such as that of a document repository, we may allow files such as .doc, .pdf, .xls, etc. In either case we want to restrict the types of files to a predefined list and disallow all other types of files. The only guaranteed manner we can enforce proper file type restrictions is through proper input validation. This validation must occur on both the client, as well as the server (input validation should always be done in both locations). The validation must check several things, including the file extension, the content-type and the file name itself.

Proper input validation must be used to ensure the file type the user is attempting to upload is an allowable file type. The easiest way to perform the first part of the file type validation is to check the extension of the file the user is attempting to upload. Figure 1 shows a sample JavaScript function that can be used to perform client-side validation of a file.

Figure 1


function CheckFileExt(fileName, allowedFileTypes)
{
 var dot;
 var fileType;

 dot = fileName.split(".");
 fileType = "." dot[dot.length-1];

 if(allowedFileTypes.join(".").indexOf(fileType) != -1)
 {
 return true;
 }
 else
 {
 alert("Invalid File Type!");
 return false;
 }
}

In order to call the validation script above we will use the OnChange event of the file input control, as seen in Figure 2.

Figure 2

OnChange="return CheckFileExt(this.value, ['gif', 'jpg', 'png', 'jpeg']);"

The OnChange event passes the file name the user is attempting to upload, as well as a comma separated list of allowed file extensions. The function seen in Figure 1, will take file name, strip the extension and compare it to the list of allowed extensions. If the extension is allowed the page will allow the user to continue. However, if the extension is not allowed a JavaScript alert box will pop-up informing the user the file type is invalid. There is one major issue with this though. If the user has turned off JavaScript in their browser it will render our validation function useless. This is why it is imperative to ensure the validation is performed not only on the client, but on the server as well.

The next area to consider for validation is the content-type and content itself. We can't solely trust a file by its extension alone, we must validate additional areas of it to ensure it is safe. It wouldn't be difficult for a malicious user to place the text seen in Figure 3 into a file and save it as a PDF document. This would allow the malicious user to bypass the file extension validation, assuming a PDF document was allowed, without the file actually being a valid PDF document.

Figure 3 The script tag below has been modified to render, rather than execute in your browser.

-%PDF < script>alert('Not A Valid PDF Document');< /script>

The text above placed into a file and saved as a PDF document, would not only bypass the file extension validation, but it would also bypass the content-type validation. Since the text contains a valid PDF signature ("-%PDF"), the content-type will assume it is a valid PDF document. The validation process must also validate the content of the file itself. By validating the actual content we would be able to make the determination that the file was not a valid PDF document.

The last area of input validation we need to look at is the actual file name. We would need to perform some validation to ensure the file name does not contain a characters that could be used maliciously. Characters such as < > /, etc. could be used maliciously to execute script or perform a directory traversal attack. Another cause for concern is a null byte(%00). Most servers interpret the null byte character as the end of a line or statement. Thus a file named "Test.asp%00.jpg", would bypass our file extension validation, and potentially our content-type validation. However, if the file were called directly in the browser by typing "http://mydomain.com/Test.asp%00.jpg". The server would interpret that everything after the should be dropped, thus the request would be changed to "http://mydomain.com/Test.asp". We'll see in the next section why this could be a major cause for concern.

Now that we have a better idea of how to perform proper validation on an uploaded file, we need determine where we are going to store the files a user has uploaded. Obviously a database is a bad place to store uploaded files. We would need to store the files in a server's file system. Most developers make the mistake of storing uploaded files directly with the web root. The primary issue with this is if a malicious user can determine the link to a file, they could possibly, depending on access permissions, directly request the file just by typing the URL into the address bar in their browser. This could potentially lead to the unnecessary disclosure of sensitive information. Another potential issue with storing uploaded files within the web root, is the possibility that the folder containing the files could allow the execution of scripts or executables.

If a malicious user were able to bypass our validation process and upload the fake PDF document, and if the file was stored within the web root, when a user loaded that document in their browser the script would execute. Now let's consider the larger issue. Let's say instead of JavaScript being placed in the PDF document we place executable ASP script code. Let's also assume we bypassed the validation by changing the file name to "Test.asp%00.pdf". If this file was stored in the web root and this folder allowed for script execution. A malicious user could directly request the file by changing the URL in their browser to "http://mydomain.com/Test.asp%00.pdf", which as mentioned earlier would be interpreted as "http://mydomain.com/Test.asp". The result would be the ASP code inside the document being executed and the result of whatever the code did, being rendered to the user's browser. The code in the file could allow a user to traverse each drive on the server, view or download documents, gain access to sensitive information, such as usernames, passwords, database connection strings, etc. The code in the file could also attempt to gain command shell access, that could allow a malicious user to execute commands on the server.

In summary the primary concern is validation, validation, validation. We, as developers, need to ensure we validate every aspect of a file that is being uploaded. This includes the file extension, the file name, the content-type and lastly the content itself. Doing all of this still doesn't guarantee the file is 100% safe, but it will go a long way in preventing malicious files form being uploaded to our servers. We also need to ensure we aren't storing the files in the web root, because doing so could allow malicious users to directly request the files in their browser, thus potentially exposing sensitive information. Finally, if we must store the files in the web root we must ensure the folder permissions containing the files do not allow for the execution of script or executable code. Adding these preventive measures will go a long way in ensuring your user's and your server won't be compromised due to malicious file uploads.

 

 

Number of views (8390)/Comments (-)

Tags:
blog comments powered by Disqus

Enter your email below AND grab your spot in our big giveaway!

The winner will receive the entire Data Springs Collection 7.0 - Designed to get your website up and running like a DNN superhero (spandex not included).

Subscribe