Tips for Secure File Uploads with ColdFusion
Allowing someone to upload a file on to your web server is a common requirement, but also a very risky operation. So here are some tips to help make this process more secure.
Don't rely on
accept attribute gives a terrible false sense of security. Every time I present on CFML Security I ask the question: If I have this code is there any way I could upload a CFM file?.
<cffile action="upload" filefield="photo" accept="image/gif,image/jpeg" destination="#ExpandPath("./photos/")#">
The answer is YES, often to the surprise of most!
The cffile accept attribute uses the mime type that your browser sends to the server. Read that again... your browser tells cffile what the mime type is. It's very easy to spoof the mime type. For example:
<cfhttp url="http://target.example.com/upload" method="post"> <cfhttpparam file="#ExpandPath("badstuff.cfm")#" mimetype="image/gif" type="file" name="photo"> </cfhttp>
For this reason you need to ensure that
cffile.serverFileExt is of an extension you allow, and one that your server will not execute.
Use a file extension whitelist rather than a blacklist, in other words you don't just check to make sure it is not a .cfm, make sure it is only one of: "jpg,png,gif". This way if someone installs PHP on your server, you don't have to update the code to block that file extension as well.
Validate that the File Extension matches File Format
You can use a Java API like JHOVE which reads the file contents to validate that it is of the asserted file format. It supports jpg, gif, pdf, tiff, and more.
In addition CF8 has the
IsPDFFile("path") functions you could use. If you do use
IsImageFile just make sure that you have upgraded your JVM to one that doesn't have the issue that can cause an image file to crash your server. See Mark Kruger's blog entry for details.
Always upload to a temp directory outside of the Web Root
Suppose I ran the same hack above with
cfhttp but you now have code in place to delete the file if the extension is incorrect. There is a slight chance that I could execute that file before you can delete it if you uploaded it into the web root (and I could predict where it would be placed).
Once you have validated the upload, you can move it to its desired location.
Keep uploaded files outside the web root
If possible keep uploaded files outside of the web root and serve them with
cfcontent. In some cases this is not possible, but seriously consider this as it does ease the risk significantly.
Remove execute permissions from upload directories
The reason for this should be obvious, but is something we often forget to do.
Upload to a static content server
If possible upload content to a server other than the application server, a server that only serves static content (for example Amazon S3).
Don't trust on the client supplied file name
The client supplied file name could possibly contain SQL Injection, cross site scripting, or CRLF Injection.
It's best to strip out non alpha numeric characters (perhaps with the exception of dash and underscore).
ColdFusion Administrator Settings
There are a few Administrator Settings that you should pay attention to related to file uploads (and large HTTP POST operations). They are under Server Settings » Settings under the heading Request Size Limits:
The first setting is the maximum size of a POST, and therefor also a file upload. The default 100mb is probably bigger than needed for most web apps, you can lower it to mitigate DOS potential. Chances are your web server is also capable of limiting the post size, on apache you can use the
LimitRequestBody directive to do this.
The next setting Request Throttle Threshold should probably be lowered to 1MB, this puts any request larger than 1mb into a throttle for synchronous processing.
The third setting Request Throttle Memory is the maximum size of request throttle queue. The default is kind of high, if you don't have a lot of large file uploads going on at the same time this should be lowered to say 50mb (it shouldn't be lower than the Maximum size of post data, or the Request Throttle Threshold, but it could be equal to the max size.). Consider that on a 32bit server, the max JVM size is typically not much bigger than 1GB, you could allow 1/5th of your server resources to be consumed by file uploads with the default setting.
If you are using the Enterprise edition of ColdFusion you can setup a sandbox for your file upload directory, and remove execute permission. This only applies to ColdFusion template execution (not PHP scripts for example).
Restrict using Web Server
Use you should limit your uploads directory to only allow static files to be requested. For example on IIS you can remove the handler mappings for CF, and then use Request Filtering to limit file extensions to a specific whitelist, so that IIS will reject any request under /images/ that is not a .gif, .png, or .jpg for example.
Do you have any additional tips?
- Risks of FCKeditor Vulnerability in CF8 - July 6, 2009
- Hotfix for CF8 FCKeditor Vulnerability Released - July 8, 2009
- ColdFusion 8 FCKeditor Vulnerability - July 3, 2009
- Firefox Aurora now Supports Content Security Policy 1.0 - May 31, 2013
- HackMyCF Scanner Updated - February 1, 2011
- CFSummit 2016 Slides
- Securing Legacy CFML - dev.Objective() 2016 Slides
- My CFSummit 2015 Slide Decks
- Adding Chrome Custom Search for CFDocs
- Disable Flash Remoting on ColdFusion Servers
- HackMyCF Adds SSL/TLS Scanner
- IncompatibleClassChangeError after ColdFusion 11 Update 5
- Scope Injection in CFML