Radiant Media Player

Secure streaming with Wowza SecureToken version 2

Last updated on May 19, 2016


Introduction

For general information on Wowza and guidance on how to use it with Radiant Media Player please refer to our working with Wowza guide.

Wowza SecureToken is a challenge/response system that helps to protect content against spoofing threats. Each connection is protected by a random key and a password (shared secret). This mechanism can be used to protect MPEG-DASH and HLS streaming.

Wowza Streaming Engine™ 4.1 and later is required to use the enhanced SecureToken functionality that's described in this article.

While this article focuses on using Radiant Media Player as a front-end player, the below instructions can be applied to any player with support for HLS or MPEG-DASH.


Secure streaming with Wowza SecureToken version 2

At any time refer to the following Wowza documentation to properly configure your Wowza server for SecureToken management.

Radiant Media Player does not support RTMP protocol using TEA (SecureToken version 1) from Wowza nor do we intend to provide support. RTMP is considered a legacy protocol for Flash-based video and provides less performance than Apple HLS to Flash with SecureToken version 2.

The following code is an implementation example of how to use SecureToken version 2 with Wowza and Radiant Media Player. This is only preliminary work. It is up to you to adapt and complement this code for your needs or to another programming language.

As clearly stated on Wowza documentation:

The client web server should generate the hash when it generates the client webpage. You shouldn't use JavaScript code in the client webpage to generate the hash as the code is visible in the webpage source and would pose a potential security risk.

As a result our implementation is based on a node/express application to generate a SHA-256 hash as it cannot be done within the player as explained above. We used node.js version 4.2.2, express 4.13.4 and Wowza Streaming Engine 4.2.0 to develop our application.

For the purpose of this example we have created a VOD application (this example could also work for live application) in Wowza engine manager (GUI) called "secured". We then went in the Playback security tab to configure our Wowza application. Here are the settings we entered:

  • SecureToken: protect all protocols using hash (SecureToken version 2)
  • Shared Secret: we generated one for the purpose of our application
  • Hash Algorithm: SHA-256
  • We do NOT tick: include client IP address in hash generation. You may add this additional security setting later but you will need to modify the hash generation script.
  • Hash Query Parameter Prefix: randomTokenPrefix
  • Client Restrictions: no client restrictions (of course you can modify this setting if you need IP white/black listing)
  • We saved our application and restart it.

Server-side hash generation code (node/express application):

var crypto = require('crypto');
var express = require('express');
var app = express();
// The shared secret as generated in our Wowza application (Playback security tab) - use your own
var sharedSecret = '9cb929910544f649';
// The path of the content - use your own
var contentPath = 'secured/smil:bbb.smil';
// The Hash Query Parameter Prefix as set in Wowza application
var customSecureTokenPrefix = 'randomTokenPrefix';
// A custom paramater to add pepper and salt to security - use your own
var customParam = 'pepperandsalt';
// Starts: Thu, 20 Aug 2015 14:40:11 GMT
var startTime = '1440081611';
// Ends: Sun, 26 Nov 2017 13:46:51 GMT
var endTime = '1511704011';
var toHash;
// Adding CORS headers
app.use('/generate-hash', function (req, res, next) {
  res.header("Access-Control-Allow-Origin",
      "*");
  res.header("Access-Control-Allow-Headers",
      "Origin, X-Requested-With, Content-Type, Accept");
  next();
});
// We get the hash at /generate-hash
app.get('/generate-hash', function (req, res, next) {
  toHash = contentPath + '?' +
           sharedSecret + '&' +
           customSecureTokenPrefix + 'CustomParameter=' + customParam + '&' +
           customSecureTokenPrefix + 'endtime=' + endTime + '&' +
           customSecureTokenPrefix + 'starttime=' + startTime;
  var hash = crypto.createHash('sha256').
      update(toHash, "utf8").
      digest('base64');
  hash = hash.replace(/\//g, '_'); 
  hash = hash.replace(/\+/g, '-');
  console.log(hash);
  res.send(hash);
});
// Listen for requests
var server = app.listen(3000, '[node-ip-address]', function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Example app listening at http://%s:%s', host, port);
});

Let us save this JavaScript file as wowzatoken.js. We then run this code with node wowzatoken.js.

Note the app.listen(3000, '[node-ip-address]' part where you may need to explicitly set your node server IP address as Wowza expects an IPv4 IP address.

Client-side Radiant Media Player code to retrieve and process the hash:

<script src="https://cdn.radiantmediatechs.com/rmp/v3/latest/js/rmp.min.js"></script>
<div id="rmpPlayer"></div>
<script>
  // Init player function once the hash has been retrieved
  var initPlayer = function (hash) {
    console.log(hash);
    var hlsUrl = 'https://streamingrmp-1479.kxcdn.com/secured/smil:bbb.smil/playlist.m3u8?' +
        'randomTokenPrefixstarttime=1440081611&' +
        'randomTokenPrefixendtime=1511704011&' +
        'randomTokenPrefixCustomParameter=pepperandsalt&' +
        'randomTokenPrefixhash=' + hash;
    console.log(hlsUrl);
    var bitrates = {
      hls: hlsUrl
    };
    var settings = {
      width: 640,
      height: 360,
      licenseKey: 'your-license-key',
      delayToFade: 3000,
      bitrates: bitrates,
      skin: 's4',
      debug: true,
      poster: 'https://www.radiantmediaplayer.com/images/poster-rmp-showcase.jpg'
    };
    var rmp = new RadiantMP("rmpPlayer");
    rmp.init(settings);
  };
  // Ajax request for the hash to our node/express app
  var requestHash = function (url) {
    var req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.onreadystatechange = function () {
      if (req.readyState === 4) {
        var response = req.responseText;
        if (req.status === 200) {
          initPlayer(response);
        } else {
          console.log('Could not get sha256 hash');
        }
      }
    };
    req.onerror = function () {
      console.log('Could not get sha256 hash');
    };
    req.send();
  };
  // Start the request to your node/express server
  var serverHashUrl = 'http://[node-ip-address]:3000/generate-hash';
  requestHash(serverHashUrl);
</script>

In production we highly recommend you put your node application on a secured port like 443 and make all requests to get the hash with HTTPS to maintain the security chain.


Troubleshooting

For basic troubleshooting steps please refer to this Wowza article. The received hash and calculated hash must be the same in your Wowza logs. Radiant Media Player scope of support does not cover troubleshooting Wowza server configuration.

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License.