Our EdgeSecurity™ solution controls the exact clients who are allowed to view a secure resource. From digital product protection to time-expiring links, ensure your content is available for authorized eyes only.
What is a Secure Token?
Imagine having a PDF file you want to ensure isn't linked from elsewhere, to do this we need to add a unique token and an expiration date. In this how-to we will be showing you how to enable Secure Tokens, show example responses and generate sample code to create secure links.
Enable EdgeSecurity™ Secure Token
-
Log into your Control Panel and click on Zones.
-
On the right hand side, click Get EdgeSecurity.
-
Checkout and pay for EdgeSecurity.
-
Click Manage on the zone to which you are adding EdgeSecurity.
-
Click the Security tab.
-
Enable EdgeSecurity, and type in a secure key. Note that this key has a limit set to 32 characters. Once done, update the settings.
-
You have successfully added EdgeSecurity to a zone.
Log into your Control Panel and click on Zones.

On the right hand side, click Get EdgeSecurity.

Checkout and pay for EdgeSecurity.

Click Manage on the zone to which you are adding EdgeSecurity.

Click the Security tab.

Enable EdgeSecurity, and type in a secure key. Note that this key has a limit set to 32 characters. Once done, update the settings.

You have successfully added EdgeSecurity to a zone.
Example Responses
Here are some example responses using an example path. Note the differing HTTP response status codes.
-
cURL without secure link:
$ curl -I zone.alias.netdna-cdn.com/foo.pdf HTTP/1.1 403 Forbidden Server: NetDNA-cache/2.2
-
cURL without secure link:
$ curl -I zone.alias.netdna-cdn.com/foo.pdf?st=YNcnQ1H0tpgCzaLQ&e=1355776589 HTTP/1.1 200 OK Server: NetDNA-cache/2.2
-
cURL with EXPIRED secure link:
$ curl -I zone.alias.netdna-cdn.com/foo.pdf?st=YNcnQ1H0tpgCzaLQ&e=1355776589 HTTP/1.1 410 Gone Server: NetDNA-cache/2.2
Sample Code
-
PHP:
<?php $secret = 'jsdkhf8fh3fewk'; $path = '/foo.pdf'; $expire = time() + 3600; // one hour valid $md5 = base64_encode(md5($secret . $path . $expire, true)); // Using binary hashing. $md5 = strtr($md5, '+/', '-_'); // + and / are considered special characters in URLs, see the wikipedia page linked in references. $md5 = str_replace('=', '', $md5); // When used in query parameters the base64 padding character is considered special. $url = "http://zone.alias.netdna-cdn.com{$path}?st={$md5}&e={$expire}"; // use this as DL url echo $url; echo "\n\n"; ?>
-
Python
from time import time import base64 from hashlib import md5 secret = 'jsdkhf8fh3fewk' path = "/foo.pdf" expire = int(time()) + 3600 hashed_string = base64.encodestring( md5( "%s%s%s" % (secret, path, expire) ).digest() ).replace("\n", "").replace("+", "-").replace("/", "_").replace("=", "") url = "http://zone.alias.netdna-cdn.com%s?st=%s&e=%s" % (path, hashed_string, expire) print url
-
Ruby:
require 'base64' require 'digest/md5' secret = 'jsdkhf8fh3fewk' path = "/foo.pdf" expire = Time.now.to_i + 3600 hashed_string = Base64.encode64( Digest::MD5.digest( "#{secret}#{path}#{expire}" ) ).gsub("\n", "").gsub("+", "-").gsub("/", "_").gsub("=", "") url = "http://zone.alias.netdna-cdn.com#{path}?st=#{hashed_string}&e=#{expire}" puts url
-
Java:
import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; import org.apache.commons.codec.binary.Base64; public class MakeURL { private static String MakeBinaryHash(String secret, String path, Long expire) throws UnsupportedEncodingException, NoSuchAlgorithmException{ String message = secret + path + expire.toString(); byte[] bytesOfMessage = message.getBytes("UTF-8"); MessageDigest md = MessageDigest.getInstance("MD5"); byte[] thedigest = md.digest(bytesOfMessage); String encoded = Base64.encodeBase64URLSafeString(thedigest); return encoded; } public static void main(String[] args) throws Exception{ String secret = "jsdkhf8fh3fewk"; System.out.println("Secret : " + secret); String path = "/foo.pdf"; System.out.println("Path : " + path); Date d = new Date(); Long expire = (d.getTime()/ 1000) + 3600; //Divide by 1000 cause java date is in milliseconds . 1 hour in future System.out.println("expire : " + expire); String md5 = "" ; try { md5 = MakeBinaryHash(secret, path, expire); System.out.println("generated md5 : " + md5); String url = "http://zone.alias.netdna-cdn.com" + path + "?st=" + md5 + "&e=" + expire.toString() ; System.out.println("genrated url : " + url); } catch (Exception e){ e.printStackTrace(); } } }
-
node.js
var md5_digest = require('crypto'); //INCLUDE CRYPTO LIBRARY var secret = "secure_token"; // YOUR SECURE TOKEN SET IN CP var path = "/PATH/TO/FILE.EXT"; var d = new Date(); var t = d.getTime() / 1000; // JS TIME IS IN MILLISECONDS SO YOU HAVE TO DIVIDE IT BY 1000 var expire = parseInt(t) + 3600; // EXPIRY IN 3600 SECONDS var md5 = md5_digest.createHash('md5').update(secret + path + expire).digest('base64'); //MD5 DIGEST md5 = md5.toString().replace("+","-").replace("/","_").replace(new RegExp("=","gm"),""); // REPLACE SPECIAL CHARACTERS +, /, = console.log("http://ZONENAME.ALIAS.netdna-cdn.com" + path + "?st=" + md5 + "&e=" + expire); //DISPLAY RESULTING URL
-
javascript on client side
You will need md5.js and encode-decode.js libraries to handle hashing and encoding.
<script type="text/javascript" src="md5.js"></script> //INCLUDE MD5.JS FUNCTION <script type="text/javascript" src="encdec.js"></script> // INCLUDE FUNCTIONS FOR BAS64 ENCODE/DECODE <script> function run(){ var secret = "secure_token"; var path = "/PATH/TO/FILE.EXT"; var d = new Date(); var t = d.getTime() / 1000; // JS TIME IS IN MILLISECONDS SO YOU NEED TO DIVIDE IT BY 1000 TO GET SECONDS var expire = parseInt(t) + 3600; // ADD EXPIRY OF 3600 SECONDS var md5 = calcMD5(secret + path + expire); // CALCULATE MD5 var base64 = decodeHex(md5); // HEX DECODE MD5 HASH var md5base64 = encodeBase64(base64).replace("+","-").replace("/","_").replace(new RegExp("=","gm"),""); //REPLACE SPECIAL CHARS +, /, = alert("http://ZONENAME.ALIAS.netdna-cdn.com" + path + "?st=" + md5base64 + "&e=" + expire); //DISPLAY RESULTING URL }
-
.NET/C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; namespace securetokens { class Program { static void Main(string[] args) { var secret = "token"; var path = "/favicon.ico"; //generate unix timestamp and add one day in seconds - expiry time Int32 unixtimestamp = (Int32)(DateTime.UtcNow.AddDays(1).Subtract(new DateTime(1970, 1, 1))).TotalSeconds; var expire = Convert.ToString(unixtimestamp); var md5 = MD5.Create(); //load string into byte array and hash it byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(secret + path + expire)); //get base64 encoded string var md = Convert.ToBase64String(data); //"+","/" and "=" are treated as special characters that need to be replaced/removed acordingly: md = md.Replace("+", "-").Replace("/", "_").Replace("=", ""); //resulting secure link: Console.Write("http://ZONE.ALIAS.netdna-cdn.com" + path + "?st=" + md + "&e=" + expire); Console.ReadLine(); } } }
-
.NET/VB
Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Security.Cryptography Module Module1 Sub Main() Dim secret = "token" Dim path = "/favicon.ico" 'generate unix timestamp and add one day in seconds - expiry time Dim unixtimestamp As Int32 = CType(Math.Truncate((DateTime.UtcNow.AddDays(1).Subtract(New DateTime(1970, 1, 1))).TotalSeconds), Int32) Dim expire = Convert.ToString(unixtimestamp) Dim md5__1 = MD5.Create() 'load string into byte array and hash it Dim data As Byte() = md5__1.ComputeHash(Encoding.UTF8.GetBytes(secret & path & expire)) 'get base64 encoded string Dim md = Convert.ToBase64String(data) '"+","/" and "=" are treated as special characters that need to be replaced/removed acordingly: md = md.Replace("+", "-").Replace("/", "_").Replace("=", "") 'resulting secure link: Console.Write("http://ZONE.ALIAS.netdna-cdn.com" & path & "?st=" & md & "&e=" & expire) Console.ReadLine() End Sub End Module
We hope this article was helpful and as always, If you have any questions or concerns about any of the topics mentioned in this article, please feel free to reach out to support - we are available 24/7 by chat or email!