Tips for Secure File Uploads with ColdFusion
By Pete Freitag
Allowing someone to upload a file to your ColdFusion or Lucee server is a common requirement, but also a very risky operation. So here are some security tips to help you write secure file upload code in ColdFusion.
Don't rely on cffile
accept
attribute
The 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 allowlist rather than a denylist, 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 IsImageFile("path")
and 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.
Sandboxes
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 allowlist, so that IIS will reject any request under /images/ that is not a .gif, .png, or .jpg for example.
Tools that can help
My company Foundeo makes some tools that can help you out here. First FuseGuard Web App Firewall for ColdFusion allows you to set an allow list of file extensions. FuseGuard runs in your Application.cfc or Application.cfm file to inspect, log and block requests before they hit your application code. This means that if someone tries to upload a cfm file to your ColdFusion application, and FuseGuard is running it would block the request, even if your application code would have allowed it. It's always best to fix your code as well, but running FuseGuard can add a nice layer of defense in front of your CFML applications.
Another tool that might help is a code security scanner, Fixinator. With Fixinator you can scan your source code for file upload vulnerabilities. You can even run Fixinator in a CI environment, so that it can scan your CFML code for security issues automatically every time you commit to version control.
Do you have any additional tips?
Tips for Secure File Uploads with ColdFusion was first published on June 24, 2009.
If you like reading about security, cffile, upload, file, or xss then you might also like:
- Risks of FCKeditor Vulnerability in ColdFusion 8
- Hotfix for CF8 FCKeditor Vulnerability Released
- ColdFusion 8 FCKeditor Vulnerability
- Firefox Aurora now Supports Content Security Policy 1.0
The Fixinator Code Security Scanner for ColdFusion & CFML is an easy to use security tool that every CF developer can use. It can also easily integrate into CI for automatic scanning on every commit.
Try Fixinator
CFBreak
The weekly newsletter for the CFML Community
Comments
@jason dean - glad you found it useful, feel free to post about this on your blog as well. The more people who read about it the better.
@mike letson - Using JavaScript validation is good for user experience but doesn't have any effect on security.
It's worth noting that you could achieve similar security on your own server, if needed, by leveraging Apache and creating a static content virtual host. You can have that virtual host limit file extensions and/or mime types and rewrite to 403-forbidden any suspicious requests.
If so, placing an Application.cfc / Application.cfm file in your images directory that blocks requests would be sufficient to prevent execution?
Or am I missing something?
Adding Application.cfc/cfm is a good idea, but it can only block ColdFusion requests, I could upload a .jsp file instead, or some other file type that might be executed server side.
You make an excellent point I haven't thought about. You can effectively disable CF from ever executing from that folder with the right application logic. However, it still leaves open the possibility that bad files can 'exist' on the server to be exploited outside of being executed by CF.
I'm fairly certain you'll need to upload the file first. You could use some JavaScript to check the extension, but since that's client side it could always be spoofed. You don't have definitive control/evidence until the file is server-side.
Check out Pete's "Always upload to a temp directory outside of the Web Root" section, above.
-Brian