Documentation

Handler: Hidden Downloads

The Hidden Downloads handler implements secure download mechanisms. This module allows to handle temporal URLs to serve hidden files.

Parameters

Parameters Type Description

secret

String

Required. Share secret between the handler and the script.

timeout

number

Optional. How long - in seconds - the URL will be valid.

Technical Description

The idea behind this handler is plain and simple. It will only serve a file if the URL has been generated by a dynamic execution script that you’ve previously written. If the script allows the user to access the file, it will generate a special encoded URL that Cherokee will handle through the Hidden Downloads module.

If the URL is invalid, is modified, or expires, Cherokee will not serve the file.

The encoding scheme is quite straightforward. It is basically the result of MD5-hash of: a shared secret string between Cherokee and the script, the relative path to the requested file (relative to the rule document root), and the current time:

'/' HEX (MD5 (Secret + URL + HEX(time))) '/' HEX(time) '/' URL

Here you have a reference implementation in Python:

 def secure_download (prefix, url, secret):
    import time, hashlib
    t = '%08x' % (time.time())
    return "/%s/%s" % (hashlib.md5(secret + url + t).hexdigest(), t + url)

The same function written in PHP would be:

function secure_download ($prefix, $url, $secret) {
  $time = sprintf('%08x', time());
  return "$prefix/".md5($secret.$url.$time)."/$time$url";
}

It is important to notice that the URLs are only valid for a period of time. If an URL expires, the server will return an error instead of the file contents. By default URLs last 60 seconds.

Note
Please note that both sample implementations count on having an URL that starts with /.

Examples

Lets imagine you have a few ISO files that you want to distribute among a certain group of people.

First, and most importantly, the ISO files ought to be outside of the WWW directory root; otherwise, anybody would be able to download them. Let’s imagine those ISO files are located under: /mnt/isos/, and the server document root is located in /var/www/.

Now it is time to configure the /downloads web directory, so it is handled by Hidden Downloads. We set a shared secret string (Abracadabra), and the document root where the real ISO files are located (/mnt/isos):

Configuration for directory /downloads

Handler

Hidden Downloads

Document Root

/mnt/isos

Secret

Abracadabra

media/images/admin_handler_secdownload.png
Hidden downloads configuration

To summarize, its a four step process: - Configure a Directory rule. Let’s say: /downloads - Set the rule to use "Hidden Downloads" handler - Set the Document Root directory (this is important!) - Set the Secret string

Next step is to write the logic that will decide what is the user given access to. For instance, check out this Pyton example:

import time
try:
    from hashlib import md5
except ImportError:
    from md5 import md5

SECRET = "Abracadabra"
DIR    = "downloads"

def secure_download (url, secret):
    t = "%08x"%(time.time())
    return '/'+ DIR +'/'+ md5(secret + url + t).hexdigest() +'/'+ t + url

# Example request
file = "test.txt"
host = "localhost"

hidden_url = secure_download('/%s'%(file), SECRET)
print "/%(DIR)s/%(file)s -> http://%(host)s%(hidden_url)s" %(locals())

According to this example, if a user tries to access /bar/foo/example.iso and access is granted, working URL such as this would be provided:

/downloads/ac003ebbb88c4fc9a75687223c72c6da/49b40a43/bar/foo/example.iso

Since the /downloads web directory is configured with this "Hidden Downloads" handler, it will check the URL to ensure that it is valid and has not expired. Then, if everything was right, it would send the /mnt/isos/bar/foo/example.iso file to the client.