Hello ClubHack readers !
This is my first Article in ClubHack and I wish to be here with some more nice articles!!
This Article is about Developing Secure File Upload Form.
Web Pages having File Upload Forms are most commonly seen. These forms are intended for users who want to upload one’s photograph, resume, application, video file or any other kind of file as per the need and requirement. If your website or web application is having such a form or if you are planning to enable file uploads then this article is for you.
I am writing this for PHP Programming Language but the logic remains same for any programming language.
Let me throw some light on why it’s important to secure your forms with file uploads. If your form is accessed by genuine user then definitely there is no harm as he would be so kind that he reads your “upload instructions” page before uploading and as per your policy would limit his file size and file format and proceed with uploading his file. On seeing successful upload message from you he would be happy.
Just think that if it’s a bad guy who is interested in hacking or harming, what can happen to your server?
Wondering how he can benefit out of your file upload page?
If your form is not validating the file size and file format properly then it could be that, an attacker can upload a file which act as web shell. Web shell is nothing but your server’s command prompt or shell prompt which can be accessible through the browser. I am not going to talk on Web shells much in this article as its already been covered in the earlier issue of clubHack, it can also be referred at http://chmagazine.sagarnangare.net/article/jul2012/php-shells. Not only web shell, one can also try to upload a worm infected file which can spread itself across your LAN and affect other servers, it could also be a keylogger or any other harmful file.
So with this awareness of file upload which could be dangerous if not coded properly, let us proceed towards understanding how to stop such mischievous file uploads through your file upload enabled forms.
General coding done for file uploading pages would have the following two files:-
1. index.php – Page which holds form with file upload enabled
2. uploadfile.php – Server Side file which processed the uploaded file like moving the uploaded file to target folder.
With the above code, the server side validation is done with which the file would successfully be uploaded if its file type is zip or rar compressed and file size is less than 2MB. Even though you are performing server side validation here, one can try to fool your server by modifying the file type field while uploading the file and successfully upload php file, exe file or any other file and succeed in exploiting your website. This can be done by renaming the file extension to something else or again by using tools like Tamper data or proxy.
So, what next? It’s been told in many tutorials that server side validation would stop most of the attacks like SQLi, XSSi etc and thus are the file upload pages protected here. But it seems that this is also not enough to secure your server.
Definitely “Server Side Validation” is the best solution to avoid most of the web attacks, but let me add another word “Perfect” to the above which makes “Perfect Server Side Validation”.
So to complete the above code with Perfect Server Side Validation, you should do something to check the file content and then judge the file type if its matching your “Upload Instructions” or not, rather than relying on the file type field value which was sent by the Browser from client side as done above.
This can be done in PHP by using mime_content_type() function. This function returns the file type by verifying the content of the file. If its PHP file but extension is .zip then it returns “text/x-php” rather than returning “application/zip”, thus the file type can be verified from server side perfectly and can control the successful upload of mischievous files.
With this the above code will look like below:
In this example, we are moving the uploaded file to a certain location based on extension and then checking the file content to cross verify the file type. It it’s not matching with our requirement then we can delete the uploaded file using @unlink and inform user to re-upload the correct file.
This mime_content_type also solves another problem, where if a user uploads a file from a windows based client, a .rar extension file is set to application/octet-stream by the browser. So we may have to add application/octet-stream in the if condition, but adding this will accept .exe file types also. So this mime_content_type will help in this scenario also to cross verify the file type so that we have only zip and rar files in our server uploaded.Thus, you can secure your server from getting hacked through web shell uploads or any other kind of mischievous file uploads.
Apart from Secure Coding, the following are some best practices to avoid problems and reduce risk.
- Rename the file received from client, so that if by mistake some mischievous file has been uploaded the client/hacker cannot access the file as he cannot get the filename.
- Disable the Director Indexing where you are storing the uploaded files.
- Have uncommon directory name to store files. Most common names are like files, upload, store, list, pictures, resumes, images, storage etc.
- Accept compressed file formats where ever possible so that automatic file execution cannot happen. If your application really needs an executable to be accepted from client, then its compulsory to accept them in compressed format only.
Your code secures your server!!