Webair CDN Secure URLs Webair provides a URL signature mechanism for securing access to your files. Access can be restricted on the basis of an expiration date (to implement short-lived URLs) and/or on the basis of the geographic location of the client requesting the download (to restrict the download of certain files to certain countries). Any tampering with the URL in an attempt to circumvent these restrictions will result in an invalid URL. URL Signatures URLs are protected from alteration by generating a MD5 digest of the valid URL and checking that against the actual URL requested. Thus, if an end user tries to alter the expiry time or allowed country for the URL the server will reject the request since the MD5 is no longer valid. A shared secret is used to prevent unauthorized regeneration of the MD5 (the "secret" is a password known to Webair and you, the owner of the protected content). Secure URLs can be generated using the provided PHP script (see genbgsec at the end of this document). Secure URLs are typically generated on the web server that serves the pages with links to the content. Any language that provides the means to generate an MD5 digest of a string can be used to implement the simple algorithm which generates the secure URL. URI Signature Algorithm A secure URI consists of several parts: The file to be served (e.g. /content/secure.ext) An expiry date (e.g. e=1182665958) An optional list of allowed countries (e.g. a=us,ca) An optional list of disallowed countries (e.g. d=ly,cd) An optional "unlock" or "global" parameter (e.g. g=1) The MD5 hash that secures the URI (e.g. h=886dbef7390dfd70aea27fd41e459e7f) The expiration time is specified as a standard POSIX timestamp (seconds since January 1 1970 00:00:00 UTC). The server compares this timestamp with the current time to determine if the URL has expired. A signature (MD5 hash) is generated for the URL using the following data: secret + file +?e=timestamp + &a=allowed-countries + &d=disallowed-countries + &g=1. The timestamp can be 0 (zero) which disables expiry of the URL (i.e. it never expires). Allowed, disallowed, and unlock parameters are mutually exclusive (i.e. it is only valid to specify one of them). For example, with: a file of /content/protected.flv with a shared secret of mysecret an allowed country of US and an expiry timestamp of 1182665958 the resulting hash, MD5(mySecret/content/protected.flv?e=1182665958&a=US) will be 886dbef7390dfd70aea27fd41e459e7f. The resulting URI for this secure download would be: /content/protected.flv?e=1182665958&a=us&h=886dbef7390dfd70aea27fd41e459e7f Restrictions by country can be specified either when the URL is created (as shown above) or by configuration settings on the Webair servers that correspond to directories (e.g. /content/us/us_only_file.ext). If content is being restricted by server-side setup then it's possible to generate a URL that overrides this so that it will work for any geographic location. This might be done, say, if an application wants to allow the user to email a link to a friend in another country. To generate such a link, append the parameter g=1 to the URI used to generate the MD5 digest: /content/us/us_only_file.ext?e=1182669982&g=1 The resulting URI would look like this: /content/us/us_only_file.ext?e=1182669982&g=1&h=0c19945a45f7e97bc4177fde22b41ebc Note the additional g=1 parameter on the URL, this is how the server knows whether to treat it as a (potentially) unlocked URL. Also note that the allowed and disallowed parameters are not specified.
PHP Sample Code for Generating Keys This PHP script implements generation of secure URIs. <?php Generate a Webair CDN secure download link for the given parameters. Compute a secure URI. INPUTS: $file - base URI (no query parameters) $secret - shared secret $expiry - expiry in seconds since January 1 1970 00:00:00 UTC $unlock - override server GeoIP security $allowed - list of allowed countries for GeoIP security $disallowed - list of disallowed countries for GeoIP security function bg_gen_secure_uri($file, $secret, $expiry = 0, $unlock = "", $allowed = "", $disallowed = "") if($file == '' $secret == '') return false; Restricting Content by Geographic Location URLs can be geographically restricted in the following ways: The allowed countries can be specified The disallowed countries can be specified A URL that would otherwise be blocked (because it's URI corresponds to an area on the server that is configured to only allow content to be downloaded by certain countries) can be unlocked so it can be viewed anywhere. This is typically combined with an expiry date so the URL will stop working at some point. Countries are specified using the two character ISO 3166 (http://www.maxmind.com/app/iso3166) country codes. For example, US specifies the United States and IE specifies Ireland. Only one of allowed, disallowed, or unlocked should be specified. The allowed and disallowed lists can contain a comma separated list of any number of country codes. // Construct the values for the MD5 salt... if ($unlock) $unlock = "&g=1"; if ($allowed) $allowed = "&a=$allowed"; if ($disallowed)
$disallowed = "&d=$disallowed"; // Generate the MD5 salt... $salt = $secret. $file. "?e=". $expiry. $allowed. $disallowed. $unlock; // Generate the MD5 hash... $m = md5($salt); // Generate the link... $uri = $file. "?e=". $expiry. $allowed. $disallowed. $unlock. "&h=". $m; return $uri;?> Error Reporting The server either successfully returns the requested content or it indicates that access was not allowed due to either expiration or country of access using HTTP code 403 ("Forbidden"). If the URL is invalid (i.e. has been altered since it was generated) then HTTP code 400 ("Bad request") is returned to the client. When 403 is returned the Webair servers can be set up to serve custom error page to the user. If this page is a PHP script (its name ends in ".php") then the server arranges for several possible parameters to be passed to it: "e" will contain the expiry date if the content has expired "a" will contain the list of allowed countries if the content was refused on because the client is not in one of those countries "d" will contain the list of disallowed countries if the client is in one of those countries The script can then either display a message to the user or (more commonly) redirect the user's browser to an alternative location. genbgsec #!/usr/local/bin/php <?php Generate a Webair CDN secure download link for the given parameters. Compute a secure URI. INPUTS: $file - base URI (no query parameters) $secret - shared secret $expiry - expiry in seconds since January 1 1970 00:00:00 UTC $unlock - override server GeoIP security $allowed - list of allowed countries for GeoIP security $disallowed - list of disallowed countries for GeoIP security function bg_gen_secure_uri($file, $secret, $expiry = 0, $unlock = "", $allowed = "", $disallowed = "") if($file == '' $secret == '') return false;
// Construct the values for the MD5 salt... if ($unlock) $unlock = "&g=1"; if ($allowed) $allowed = "&a=$allowed"; if ($disallowed) $disallowed = "&d=$disallowed"; // Generate the MD5 salt... $salt = $secret. $file. "?e=". $expiry. $allowed. $disallowed. $unlock; // Generate the MD5 hash... $m = md5($salt); // Generate the link... $uri = $file. "?e=". $expiry. $allowed. $disallowed. $unlock. "&h=". $m; return $uri; if($argc < 4) echo "Usage: $argv[0] file secret timeout [allowed_countries] [disallowed_countries] [unlock]\n"; // Read in the parameters... $file = $argv[1]; $secret = $argv[2]; $timeout = $argv[3]; $allowed = $argv[4]; $disallowed = $argv[5]; $unlock = $argv[6]; // Convert timeout in seconds to UTC timestamp... if($timeout) $now = time() - date('z'); // use UTC time since the server does $expiry = $now + $timeout; else $expiry = 0; if ($allowed && $disallowed) echo $argv[0]. ": allowed and disallowed countries are exclusive\n"; if ($unlock && ($allowed $disallowed)) echo $argv[0]. ": unlock and allowed or disallowed countries are exclusive\n";
$url = bg_gen_secure_uri($file, $secret, $expiry, $unlock, $allowed, $disallowed); if ($url) echo "$url\n"; else echo "Could not generate a URI with those parameters\n";?>