How to Create Secure Download Link Urls via Nginx

Rahul juneja
2 min readJul 14, 2020

Current Url: https://example.com/files/video/data.mp4

Final Url: https://example.com/files/video/data.mp4?md5=HASH_HERE&expiry=UNIX_TIMESTAMP

There are two aspects to implement this :

  1. Add Location Directive in Nginx vhost to secure files in a loaction

In this section we’ll first do the authorization of links. If link doesn’t have valid md5 hash and expires query string then the response header would return 403. And if it is valid but expired then it returns 410.

location /files {
root /var/www;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr enigma";

if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}

Explain:

$secure_link_expires — Unix Timestamp of future 10 digit (e.g. 1895776532)

$uri — /files/video/data.mp4 (started from slash)

$remote_addr —ipv4 or ipv6 ip (e.g 127.0.0.1)

enigma — it is a secure text. You can set it your own

Note: In ubuntu you may have to install sudo apt-get install nginx-extras to enable secure links

2. Now lets create the Secure Link Url

In PHP

<?php $expires = 1895776532;  # e.g. 2 hours url expiry would be time()+7200; 
#Test timestamp is GMT Sunday, January 27, 2030 8:35:32 PM
$domain = 'https://example.com';$uri = urldecode('/files/video/data.mp4'); #uri$ip = '127.0.0.1'; #fetch client ip and insert it here dynamically$secure_text = 'enigma'; #change according to nginx directive;function getSecureHash($ip, $uri, $secure_text, $expires){
$str = $expires.$uri.$ip.' '.$secure_text;
$tmp = md5( $str, true );
$tmp1 = base64_encode( $tmp );
return str_replace( array('+', '/', '='), array('-', '_', ''), $tmp1 );
}
$url = "$domain$uri?md5=".getSecureHash($ip, $uri, $secure_text, $expires)."&expires=$expires";
echo $url;
#prints https://example.com/files/video/data.mp4?md5=-nw0Q-e6EPFYGlgLqlBzgw&expires=1895776532
# this url expires on GMT Sunday, January 27, 2030 8:35:32 PM

IN Node.Js

var crypto = require("crypto");

function generateSecurePathHash(expires, url, client_ip, secret) {
if (!expires || !url || !client_ip || !secret) {
return undefined;
}

var input = expires + url + client_ip + " " + secret;
var binaryHash = crypto.createHash("md5").update(input).digest();
var base64Value = new Buffer(binaryHash).toString('base64');
return base64Value.replace(/=/g, '').replace(/+/g, '-').replace(///g, '_');
}

This is it. Now you have secure and unique url for every download.

--

--