Mongrel_secure_download GemPlugin

The need to send secured files in a fast and reliable way is common.

Sending a file from inside of a web application can be slow and also utilizes an entire application thread/process until the user is done downloading the file. For large files this is inefficient. The other option is to have the web server itself send the files as normal static content. This is faster but means that the files have to be in a web accessible public directory so that if someone guessed the URI of a file they could gain access to it. This is not a reasonable solution for situations where files need to be secured against unauthorized downloading.

This handler addresses the problem of having a fast and secure download mechanism for web applications. The mechanism works by having the application generate a special URI containing a token that is only valid for a certain period of time. The server then recognizes this URI and generates a token using the parameters passed in and checks for a match before sending the file to the user. The key to the process is the secret string that both the server and the application are aware of.

The URI generated has a path of the following format:

<uri-prefix>/?token=<token>&relative-path=<relative-path>&timestamp=<timestamp>

<uri-prefix> is a directory that does not exist in the directory structure of the application but does exist in the directory structure of the server. example: /downloads

<relative-path> is the path to the file being requested, relative to the path at which the web server is running. The web server must have permissions to read the file. example: /files/your_secured_file.txt

<timestamp> is the number of seconds since epoch until the time when this download expires example (in ruby on rails): 1.minute.from_now.to_i

<token> is the SHA1 hash of the concatenation of the following items: 1) the secret string defined in the configuration script 2) the relative path to the file 3) the timestamp

To use the plugin you need to do the following:

1) setup the handler within a configuration script and pass in the secret string.

example configuration script:

uri “/download”, :handler => plugin(‘/handlers/securedownload’,=> “my_secret_string”)

2) In your application, form a secured URI by creating the proper parameters and perform an SHA1 hash of the parameters to create the proper token

example code (ruby on rails): require ‘digest/sha1’

secret_string = ‘my_secret_string’ uri_prefix = ‘/downloads’ relative_path = ‘/files/secret_document.pdf’ timestamp = 1.minute.from_now.to_i token = Digest::SHA1.hexdigest(secret_string + relative_path + timestamp) uri = “#uri_prefix/?token=#token&relative-path=#relative_path&timestamp=#timestamp”

3) Start mongel by passing in the location of the configuration script from step 1 with the -S command line switch

example:

mongrel_rails start -S config/secure_download_config.rb

Error messages

If any of the parameters in the URI or the secret_string are missing the handler returns a 500 Application Error.

If the token passed in as a parameter does not match the token generated by the handler (if someone tries to guess the token) the handler returns a 403 Forbidden error.

If the timestamp is earlier than the current server time, meaning that the file is no longer a valid download then the handler returns a 408 Request Time-out Error. This error is not technically correct but it makes the most sense in the context of the handler.