TracNav
Core Features...
- Configuration File Syntax
- Configuration Options
- Change Root
- Performance
- PerformanceFastCGI
- SSL
- Traffic Shaping
- Using SMP
Modules...
- mod_accesslog
- mod_access
- mod_alias
- mod_auth
- mod_cache
- mod_cgi
- mod_cml
- mod_compress
- mod_deflate
- mod_dirlisting
- mod_evasive
- mod_evhost
- mod_expire
- mod_extforward
- mod_fastcgi
- mod_flv_streaming
- mod_geoip
- mod_magnet
- mod_mem_cache
- mod_mysql_vhost
- mod_proxy
- mod_redirect
- mod_rewrite
- mod_rrdtool
- mod_scgi
- mod_secdownload
- mod_setenv
- mod_simple_vhost
- mod_ssi
- mod_status
- mod_trigger_b4_dl
- mod_userdir
- mod_useronline
- mod_usertrack
- mod_webdav
Modules (1.5 only)...
- mod_proxy_core
- mod_sql_vhost_core
- mod_uploadprogress
- mod_deflate
Internals...
- FastCGI state-engine
- Plugin interface
- HTTP state-engine
Additional...
- User written Modules
Secure and Fast Downloading
Module: mod_secdownload
Options
secdownload.secret = <string> secdownload.document-root = <string> secdownload.uri-prefix = <string> (default: /) secdownload.timeout = <short> (default: 60 seconds)
Description
there are multiple ways to handle secured download mechanisms:
- use the webserver and the internal HTTP authentication
- use the application to authenticate and send the file through the application
Both ways have limitations:
webserver:
- + fast download
- + no additional system load
- - inflexible authentication handling
application:
- + integrated into the overall layout
- + very flexible permission management
- - the download occupies an application thread/process
A simple way to combine the two ways could be:
- app authenticates user and checks permissions to download the file.
- app redirects user to the file accessable by the webserver for further downloading.
- the webserver transfers the file to the user.
As the webserver doesn't know anything about the permissions used in the app, the resulting URL would be available to every user who knows the URL.
mod_secdownload removes this problem by introducing a way to authenticate a URL for a specified time. The application has to generate a token and a timestamp which are checked by the webserver before it allows the file to be downloaded by the webserver.
The generated URL has to have the format:
<uri-prefix>/<token>/<timestamp-in-hex>/<rel-path> which looks like "yourserver.com/bf32df9cdb54894b22e09d0ed87326fc/435cc8cc/secure.tar.gz"
<token> is an MD5 of
- a secret string (user supplied)
- <rel-path> (starts with /)
- <timestamp-in-hex>
As you can see, the token is not bound to the user at all. The only limiting factor is the timestamp which is used to invalidate the URL after a given timeout (secdownload.timeout).
If the user tries to fake the URL by choosing a random token, status 403 'Forbidden' will be sent out.
If the timeout is reached, status 410 'Gone' will be sent. This used to be 408 'Request Timeout' in earlier versions.
If token and timeout are valid, the <rel-path> is appended to the configured (secdownload.document-root) and passed to the normal internal file transfer functionality. This might lead to status 200 or 404.
Example
Application
Your application has to generate the correct URLs. The following sample code for PHP should be easily adaptable to any other language:
<?php
$secret = "verysecret";
$uri_prefix = "/dl/";
# filename
# please note file name starts with "/"
$f = "/secret-file.txt";
# current timestamp
$t = time();
$t_hex = sprintf("%08x", $t);
$m = md5($secret.$f.$t_hex);
# generate link
printf('<a href="%s%s/%s%s">%s</a>',
$uri_prefix, $m, $t_hex, $f, $f);
?>
A ruby on rails example, used in the context of a helper:
def gen_sec_link(rel_path) rel_path.sub!(/^([^\/])/,'/\1') # Make sure it had a leading slash s_secret = 'secret' # Secret string uri_prefix = '/dl/' # Arbitrary download prefix timestamp = "%08x" % Time.now.to_i # Timestamp, to hex token = MD5::md5(s_secret + rel_path + timestamp).to_s # Token Creation '%s%s/%s%s' % [uri_prefix, token, timestamp, rel_path] # Return the properly formatted string end
So in a view or helper: <%= link_to "Private Image", gen_sec_link("path/from/download-area/someimage.img") %>
A generic Python example, usable with Django or any other Python web framework:
def gen_sec_link(rel_path):
import time, hashlib
secret = 'verysecret'
uri_prefix = '/dl/'
hextime = "%08x" % time.time()
token = hashlib.md5(secret + rel_path + hextime).hexdigest()
return '%s%s/%s%s' % (uri_prefix, token, hextime, rel_path)
Webserver
The server has to be configured in the same way. The URI prefix and secret have to match:
server.modules = ( ..., "mod_secdownload", ... ) secdownload.secret = "verysecret" secdownload.document-root = "/home/www/servers/download-area/" secdownload.uri-prefix = "/dl/" secdownload.timeout = 1

