Secure file downloads

April 21, 2008

I was recently saw a post on the coldfusion-how-to Yahoo group about secure file downloads. Part of the answer that was posted was:

<cfheader name="Content-Disposition" value='attachment; filename="#url.filename#"'>
<cfcontent type="#mimeType#" file="#url.path##url.filename#">

As you can see the file path can be passed as a URL parameter, meaning that you have potentially allowed access to your entire filesystem. A hacker can easily see what type of server your site is hosted on by looking at the host headers and then do something like this:

download.cfm?path=C:\&filename=boot.ini

Top tip: Never pass the filepath in the form or url parameters.

So, how do you allow users to download a file without linking directly to it? Well, cfcontent is the way to go although it is not very efficient if you are serving large files, and make sure that the files are outside of your web root.

I personally would not pass anything in the url that gave away the filename or file location. Instead, I have a table in my database which has a primary key and columns to hold the filename and directory. Use a unique identifier for the primary key instead of an integer, just so that a hacker can't try sequential numbers to access other files. You download link will now look something like:

download.cfm?id=BE1CFA33-76EB-481B-8252-18F247624C5F

If your'e stuck with using integers for your primary key then use the Encrpyt and Decrypt functions.

Obviously you also need to add some code to your download.cfm script to ensure that the user is authorised to download files, otherwise the link would work for everyone making your efforts worthless!

If you want even better security (and you should!) I would recommend, that you make the entry in your database unique to the visitor. To do this we need to add an additional table to the database specifically for downloads.

This means that we can delete the record from the table once the url has been called, meaning that it can only be used once. If you think that is too restrictive then you can always have an expiry date/time for the database record, or allow the link to be used x amount of times before deleting it.

At the end of the day even if you implement these steps, then the user can still email the file once they've downloaded it! If you are serving PDF files, then the cfpdf tag has some useful in-built security which is well worth reading up on.


2 comments

  1. I've found it easy enough to encrypt the location of the file using <cfencrypt> and then pass that to my template\event to decrypt and then download the file. I will typically generate a passphrase and keep in session to use with the download scheme. After the session has expired, the url that user used to download becomes invalid.

    Comment by JAlpino – April 21, 2008
  2. Hi JAlpino,
    Thanks for your thoughts, your solution is a good one if the user is logged in. The way that I was talking about would also work for an online shop offering digital downloads where the user is emailed the link. This way I don't have to rely on sessions and I also have the added benefit of being able to store in the database when the file was downloaded (you would need to flag the record as deleted instead of actually deleting it).
    In the past I have used a method similar to one that you're using but I encrypted the current date and time so that the link would expire.

    Comment by John Whish – April 21, 2008

Leave a comment

If you found this post useful, interesting or just plain wrong, let me know - I like feedback :)

Please note: If you haven't commented before, then your comments will be moderated before they are displayed.