Securing your downloads with mod_xsendfile

October 19, 2009 at 9:23pm.

This entry is about Programming

4 comments.

I know I haven’t been the best blogger lately (in part because I’ve been blogging over at my new job). So to help remedy that I am going to try posting more short tips and snippets. These are things I want to be able to refer back to myself, and that I think might be useful to other people.

Why use mod_xsendfile?

In many case you have files available through your webapp that should only be accessible to certain people. You don’t want to rely on security through obscurity (throwing them all in a public folder, but only showing the links to certain visitors). Although that will deter casual users from getting ahold of the forbidden files, once someone has the link they could post it anywhere and your security is blown. What you want to do is to squirrel the files away outside of your publicly-accessible folder and then give them out as needed once a user is validated by whatever authentication method you are using.

Apache’s mod_xsendfile module (inspired by lighthttpd’s X-Sendfile) is the tool for this job. By intercepting http requests with the “X-Sendfile” header and outputting the contents of a specified file, it both enables per-file authentication and is more efficient than processing the file contents through your server-side script and sending it to the browser that way. The file path you give to mod_xsendfile doesn’t need to be in the server’s public folder, so it is a very secure way to store sensitive files.

Installing on Mac OS X

(Installing on any Apache server will be similar, but I use OS X for development, so that is what these instructions are based on.)

Prerequisites:

  • Xcode Developer Tools (which is can be installed from your OS X DVD)
  • Basic knowledge of the command line

Download the source

Open up the Terminal and create a folder to hold the mod_xsendfile source files:

mkdir ~/src
cd ~/src

Now download the source and uncompress it:

curl -O http://tn123.ath.cx/mod_xsendfile/mod_xsendfile-0.9.tar.gz
tar xzvf mod_xsendfile-0.9.tar.gz
cd mod_xsendfile-0.9

Compile and install it:

sudo apxs -cia mod_xsendfile.c

You will have to enter your password and it will do its thing. Finally you need to enable the module. You can choose to do this globally in your httpd.conf file or for just a particular project in a .htaccess file. Either way, the syntax is the same:

# Enable mod_xsendfile
XSendFile On
# Allow sending files from above the requested uri
XSendFilePath /absolute/path/to/the/files/

(XSendFilePath is only necessary if the files you want to serve using mod_xsendfile are outside of your public web root folder.)

Finally restart Apache by opening your System Preferences and in the Sharing pane unchecking and re-checking the “Web Sharing” option.

Sending a file

This part is easy. Just set the x_sendfile header with the path to the file you want to send. Make sure you check first if the current user is allowed to access the file! They will not see the xsendfile header or have any way of knowing where the file is actually stored.

In PHP

header("X-Sendfile: $filePath");
header("Content-Disposition: attachment; file=$fileName");

In Ruby on Rails

response.headers['X-Sendfile'] = @file.path
response.headers['Content-Disposition'] = "attachment; filename=#{@file.file_name}"
render :nothing => true

Comments:

Anand gravatar

Anand on November 1, 2011 at 2:45am#1

I get this problem in ubuntu when I try to restart apache.

Invalid command ‘XSendFileAllowAbove’

EliVZ gravatar

EliVZ on November 1, 2011 at 9:08pm#2

Anand- It seems that the configuration options for mod_xsendfile have changed since I wrote this tutorial. Now you need to use XSendFilePath with the absolute path to the directory where you will serve the files from, instead of XSendFileAllowAbove. Something like:

XSendFilePath /var/www/sitename.com/protectedfiles/

I will update the post.

Jácome gravatar

Jácome on November 17, 2011 at 11:23am#3

Hi!

Thanks by the post, but I believe version 0.9 works with XSendFileAllowAbove and after 0.10 with the new XSendFilePath (https://tn123.org/mod_xsendfile/).

In fact, in my Mac I can run my app with the 0.9 version, but not with versions with XSendFilePath. Any ideas why?

Thanks

EliVZ gravatar

EliVZ on November 18, 2011 at 1:13pm#4

Jácome- You are correct, XSendFilePath is a more recent addition. If you are still using v0.9 you will need to following line instead:

XSendFileAllowAbove on

Got something to say?