How to secure CDN content with secure tokens

Secure tokens are among the most effective tools to protect your images, videos and downloads from unauthorised access and hot linking. Once enabled, the feature will cause PUSHR to validate every request from every visitor and serve the requested content only to those who can provide a valid access token. 

Tokens can be generated to protect files and entire directories. 

How does it work

Your website, service or app generates a unique token to authenticate the request for a file or directory. The IP of the visitor, the path to the content, the expiration time of the token and a secret passphrase are used. The successfully generated token hash and it's expiration time are then inserted into the URL to the content that is being protected. The path to the file or directory is then appended as a query string to the resulting URL. When PUSHR receives the request it attempts to recreate the token based on the provided information. If the passed hash matches the recreated hash the visitor is allowed to retrieve the requested file. If the token is not valid, is expired, or is missing, an error HTTP 403 is returned and access is blocked. 

File token vs. Title token

Based on the type of content that is being protected, PUSHR distinguishes two types of tokens. For single files like mp4 videos for example, the entire path to the protected video can be used. This way the token would be valid only for the given file, but will be invalid for other files in the same directory. We refer to this as a file token, and it is how you'd usually want to protect most of your files. 


However, some content types like HLS video on demand consist of video fragments (.ts files) and one or more manifest files (.m3u8). These usually reside in the same directory, or in subdirectories of the main directory. If a file token is generated for the master manifest file, it will only work for it but not for the .ts and other .m3u8 files linked inside. This would cause the HLS video to be blocked even for authorised viewers. To avoid this and still protect the HLS video, only the path to the parent directory should be used in the token. This is refered to as a title token.

Generating file tokens

The PHP code below generates a file token for a file named video.mp4, which is accessible from the following CDN URL:

https://c0999z0999.r-cdn.com/uploads/videos/2023/12/18/2630811/video.mp4

The token is set to be valid for one hour after which it will no longer work. This is the snippet that generates the token:

$secret = '9250b984b0c4080854360bf26bb1de2c7141f968';
$host = 'https://c0999z0999.r-cdn.com';
$path = '/uploads/videos/2023/12/18/2630811/'; 
$file = 'video.mp4'; 
$ip = $_SERVER['REMOTE_ADDR']; 
$exp = time()+3600; 
$md5 = base64_encode(md5($secret.$exp.$path.$file.$ip, true)); 
$md5 = strtr($md5, '+/', '-_'); 
$md5 = str_replace('=', '', $md5);
$link = $host.'/'.$md5.'/'.$exp.$path.$file;
    
echo $link;

The resulting link to video.mp4 is now held inside the $link variable. It looks like this:

https://c0999z0999.r-cdn.com/EMTFuYHJOq_PtCYStfBt3g/1703602087/uploads/videos/2023/12/18/2630811/video.mp4

In the URL above, the newly generated token is included first:

EMTFuYHJOq_PtCYStfBt3g

The expiration timestmap is included second. It is in unix epoch format:

1703602087

The file video.mp4 will be protected by the token and PUSHR will rewrite the link to the correct URL internally. All other files in the /uploads/videos/2023/12/18/2630811/ directory will not be accessible unless a file token has been generated individually for each one of them. 

Generating title tokens

To generate a title token that would work with HLS video content or provide access to all files in a single directory, the tokens need to be generated differently. The two main changes are:

• The file is excluded from the generation of the MD5 hash

• An additional query parameter pushr is passed in the URL

In the following example, a HLS video has it's main manifest file in a directory, and the manifests for the different video resolutions with their corresponding .ts files in subdirectories. The snippet will generate a token that would work for the following structure:

/uploads/videos/2023/12/18/2630811/playlist.m3u8 /uploads/videos/2023/12/18/2630811/360p/... /uploads/videos/2023/12/18/2630811/720p/... /uploads/videos/2023/12/18/2630811/1080p/...

$secret = '9250b984b0c4080854360bf26bb1de2c7141f968';
$host = 'https://c0999z0999.r-cdn.com';
$path = '/uploads/videos/2023/12/18/2630811/'; 
$file = 'playlist.m3u8';
$ip = $_SERVER['REMOTE_ADDR']; 
$exp = time()+3600; 
$md5 = base64_encode(md5($secret.$path.$ip.$exp, true)); 
$md5 = strtr($md5, '+/', '-_'); 
$md5 = str_replace('=', '', $md5);
  
$link = $host."/".$md5."/".$exp.$path.$file."?pushr=".$path;

 The resulting link to the protected HLS video would look like:

https://c0999z0999.r-cdn.com/3HVsqx08yT9Z/1703602087/uploads/videos/2023/12/18/2630811/playlist.m3u8?pushr=/uploads/videos/2023/12/18/2630811/

 Note: Title tokens require relative links inside manifest files.