Recent Comments
Archives
Visitors
  • 46687This month:
  • 1816Today:
  • 21Currently online:



LeaseWeb CDN

“HTTP secure link” using OpenResty Nginx module

Whenever you generate a link on your website to let your visitor download some content, you run into the risk that people will start sharing that link with others. If you want to discourage that you can require the user to login before downloading. If this is not an option for you then you can generate links that are only valid for a few seconds. This is a feature that Nginx supports using the Nginx module HttpSecureLinkModule.

Standard HttpSecureLinkModule

You can specify a Unix timestamp on which the link should no longer be valid; you add this timestamp to the query string like this:

http://localhost/package.zip?e=1402056061&s=be0c677337fec22820b916e48c54755e

In this URL (that uses ‘GET’ parameters) the ‘e’ parameter is the expiry timestamp and the ‘s’ parameter is the signature. This signature is calculated by taking a secret and appending the expiry timestamp to it and calculating a hash over that.

$signature = md5( $secret . $path . $expiry );

OpenResty Nginx modules

But what if you want to use a variant on that? For instance, if you want to restrict on certain networks or use a different hashing algorithm for the signature? My idea was to use the excellent building blocks from the set-misc-nginx-module that is made by Yichun Zhang (a.k.a. “agentzh”). This Nginx module is not included in Nginx by default, but is a part of the OpenResty Nginx distribution or as Yichun Zhang explaines:

By taking advantage of various well-designed Nginx modules, OpenResty effectively turns the nginx server into a powerful web app server. OpenResty is not an Nginx fork. It is just a software bundle. – openresty.org

We did 3 pull requests to the “set-misc-nginx-module” that allow for the needed functionality. You can compile this Nginx module into your Nginx by pointing the “–add-module” configure option to your checkout of this module. We have added the “set_encode_base64url”, “set_decode_base64url”, “set_expired” and “set_ip_matches” directives for building a custom secure link Nginx module.

Installation instructions

The configuration for the Nginx module would be like this:

# GET /?e=1893452400&n=MC4wLjAuMC8w&s=QVvNrcn-j4smvOFhuPTUU7EgoI8
# returns 403 when signature on the arguments is not correct OR
# when expire time is passed or network does not match.
# It is an alternative to the HttpSecureLinkModule in Nginx.
# This example has expiry "2030-01-01" and network "0.0.0.0/0".
location / {
  set_hmac_sha1 $signature 'secret-key' "e=$arg_e&n=$arg_n";
  set_encode_base64url $signature;
  if ($signature != $arg_s) {
    return 403;
  }
  set_expired $expired $arg_e;
  if ($expired) {
    return 403;
  }
  set_decode_base64url $network $arg_n;
  set_ip_matches $ip_matches $network $remote_addr;
  if ($ip_matches = 0) {
    return 403;
  }
  root /var/www;
}

Where the PHP code to generate the link would be:

<?php
function base64url_encode($s)
{ return rtrim(strtr(base64_encode($s),"+/", "-_"),"=");
}
$secret = "secret-key";
$expiry = strtotime("2030-01-01 00:00:00");
$network = base64url_encode("0.0.0.0/0");
$query = "e=$expiry&n=$network";
$signature = base64url_encode(hash_hmac('sha1',$query,$secret,true));
$url = "http://localhost/?$query&s=$signature";
echo "$url\n";

Output would be:

http://localhost/package.zip?e=1893452400&n=MC4wLjAuMC8w&s=QVvNrcn-j4smvOFhuPTUU7EgoI8

5 Responses to ““HTTP secure link” using OpenResty Nginx module”

  • campones:

    hello,

    This looks pretty similar to what I am trying to achieve

    I m following this nginx secure link how to

    http://nginx-rtmp.blogspot.fr/2013/06/secure-links-in-nginx-rtmp.html

    But the owner doesn’t provide a php script to make it working, beside his bash command..

    I d need some help creating the right php script to produce the right hash to secure my videos, do you have any ideas?

    thanks

  • Maurits van der Schee (Innovation Engineer):

    @campones: Here you go:


    $mysecretkey = "mysecretkey";
    $path = "myapp/mystream";
    $expiry = strtotime("+1 hour");
    $b64 = base64_encode(md5($mysecretkey.$path.$expiry,true));
    $b64u = rtrim(str_replace(array('+','/'),array('-','_'),$b64),'=');
    echo "rtmp://localhost/$path?e=$expiry&st=$b64u\n";

    Hope it helps.

  • campones:

    Hello

    I have been testing your code and it works great! Can’t thank you enough!

    Hope it s okay if I link you back on that forum to share your solution, might help many others..

  • Maurits van der Schee (Innovation Engineer):

    @campones: I’m glad it helped you. Please add the link. I’m happy to help others as well..

Leave a Reply