AppSec Blog

8 Basic Rules to Implement Secure File Uploads

The IIS semicolon file extension issue prompted me to jot down some of the rules to implement file uploads securely. This is in particular complex as there is usually no easy way to validate the content of the file.

The overall goal is to build a set of defensive layers that tightly control the process of uploading the file and later retrieval of the file. The user will always interact indirectly with the file and never directly access the file system without application control.

1. Create a new file name

Do not use the user supplied file name as a file name on your local system. Instead, create your own unpredictable file name. Something like a hash (md5/sha1) works as it is easily validated (it is just a hex number). Maybe add a serial number or a time stamp to avoid accidental collisions. You may add a secret to the name to make it harder to guess the file name. If you need to keep the original file name: use a look-up table to link the validated user supplied file name to the server created name.

2. Store the file outside of your document root

If your document root is /var/www/html, create a directory /var/www/uploads and use it to store uploaded files. That way, an attacker will not be able to retrieve the file directly. This will allow you to provide fine grained access control. The file will not be parsed by the server's application language module but the source of the file will be streamed.

3. Check the file size

You should set a maximum file size in the upload form, but remember: It is just advisory. Make sure to check the file size after the upload completed. Be in particular careful if you allow the upload of compressed files and later uncompress them on the server. This scenario is very hard to secure.

4. Extensions are meaningless

The motivation for this post is the ';' issue in IIS. However, even Apache doesn't always behave the way you expect it to. Try 'something.php.x' in Apache and chances are that php code will be executed. Its a feature ? . If you stream a file back to the user, the extension isn't what matters, but the Content-Type header and the file's header. It is best to use the "file" command on unix to check the file type. But even this is not fool proof. It will just check the first few bytes. In PHP for example, a file may start with a GIF header, but later if the PHP engine sees a "<?php" tag, it will happily interpret an embedded PHP script.

5. Try a malware scan

The extension is right, and you checked that the file is actually a valid JPEG file per it's header. However, it could still be a malicious JPEG using one of the many image parser bugs to exploit clients downloading the file. There is no great defense against this as far as I am aware. One possible work around is to "rebuild" the file. Convert the JPEG to a GIF and back to a JPEG. This will likely strip out any malicious feature. But this technique could expose your servers to just the same image parser bugs.

6. Keep tight control of permissions

Any uploaded file will be owned by the web server. But it only needs read/write permission, not execute permissions. After the file is downloaded, you could apply additional restrictions if this is appropriate. Sometimes it can be helpful to remove the execute permission from directories to prevent the server from enumerating files.

7. Authenticate file uploads

File uploads, in particular if these files are viewable by others without moderator review, have to be authenticated. This way it is at least possible to track who uploaded an objectionable file.

8. Limit the number of uploaded files

Many developers limit the file size, but not all limit the number of files uploaded in a request. Make sure to apply reasonable limits. But be also ready for a DoS attack that just uploads a large number of small files. Pick an appropriate directory structure to limit the number of files per directory and pick an appropriate file system.


Let me know if you can think of other issues to consider. Some depend on the application, but the eight above are generic. For example, if you deal with XML files you can validate them against a schema. A text file can be validated based on dictionaries. Particular image formats can be analyzed more closely for malicious content. For PDFs, you can strip out javascript which often causes problems and for HTML you could use libraries like HTML purifier. Using a distinct upload partition can help against having a denial of service attack impact other parts of the system and it will also allow for additional access control. A human moderator may be advisable if inappropriate content is a problem.

Finally: Remember the #1 rule of good web application security. All users are evil!


Posted February 16, 2010 at 9:07 PM | Permalink | Reply

Karim Said

All really good points. Thank you.
Some other possibilities:
* Whenever possible, avoid uploading the file at all. Simply parsing files in as bitstreams and pulling only the specific information you need can help to limit the possibility of malicious code getting anywhere near your system. Plus, the file will never have to live anywhere on your box.
* If it's functionally applicable, offer a pre-formatted template to users. Encode the template in some way that an attacker would have a difficult time spoofing. Upon upload, just validate the file is what you're expecting or dump it.

Posted August 4, 2010 at 4:45 AM | Permalink | Reply


All great tips. Thanks

Posted October 26, 2010 at 9:18 PM | Permalink | Reply


Keep tight control of permissions"
I'm all for that, but some servers wont allow uploading of anything unless permissions are set to 777. Is there a way to go around that ''cant write, permission denied' thing?
Great tips, I use most of them!

Posted December 5, 2016 at 4:18 PM | Permalink | Reply

Andreas Schtz

Thank you very much for this article!
Another method I found on the internet to prevent the execution of PHP code that was uploaded by a user is to set certain restrictions in the .htaccess file.
It is also claimed that it is possible thereby

Posted May 5, 2017 at 4:23 PM | Permalink | Reply

Joe Smith

Great article!
Are there any known occurrences of a ''DoS attack that just uploads a large number of small files' as part of a single request (referenced in rule 8) happening in the wild?

Post a Comment


* Indicates a required field.