多协议、性能稳定、丰富API的流媒体服务器软件
在播放Wowza的输出流时,如何使用secureToken对播放URL做验证?
wowza Streaming Engine 对 SecureToken 播放保护做升级(之前只针对rtmp协议),现在它支持了所有的流传输协议,并且包含了一个新的用来生成 security token的hashing 计算选项。 SecureToken 是一个 challenge/response 系统,用来对你的流媒体服务做URL验证层面的保护。每一个播放请求都被一个随机码和共享密钥保护。

目录


综述
Wowza Streaming Engine的SecureToken功能的相关配置
SecureToken的url查询参数
生成Hash code
Flash 播放器端的SecureToken设置
SecureToken 相关参数参考
SecureToken 查询参数在编码后被返回到Submanifest中
在log日志中会显示相关配置参数
故障排查
打印Log
Hash code不匹配时拒绝会话请求

综述


Wowza Streaming Engine (4.1.0 及以上版本) 有一个升级版的SecureToken 功能,它可以用一个security token提供针对播放流的保护。 你可以设置使用不同的Hash算法来生成security token,支持的算法包括如下:

  • SHA-256

  • SHA-384

  • SHA-512

当播放器请求一个Wowza Streaming Engine的流时,这个Url需要携带一些SecureToken 查询参数, 其中一个是经hash算法计算后的值,它由播放器端生成的。 这个Hash的计算,其原始字符串是根据content path、SecureToken 查询参数以及共享密钥的组合而形成的。当Wowza收到请求后,SecureToken模块就会根据content path、SecureToken 查询参数以及功能密钥来计算Hash值。 然后Wowza就会将自己计算的Hash值和来自播放请求中的Hash值做对比,如果不匹配,则请求被拒绝。

Wowza Streaming Engine的SecureToken功能的相关配置


这个部分向您介绍了如何在Wowza Streaming Engine Manager中为自带的vod应用配置SecureToken播放保护功能。

  1. 确定Wowza Streaming Engine Manager处于正常运行状态,要了解更多,请参考Wowza Streaming Engine 软件的启动和停止.

  2. Applications菜单,点击vod, 然后点击Playback Security.



    点击Edit来访问SecureToken配置选项。

  3. SecureToken部分,选择你要采用的secure token 播放保护的类型。 我们推荐你选择Protect all protocols using hash (SecureToken version 2). 它可以适用于所有流传输协议,并使用了最新的Hash算法。



    如果只是针对rtmp协议的,可以选择Protect RTMP protocol using TEA (SecureToken version 1).

  4. Shared Secret, 输入共享密钥(有效字符包括a - z, A - Z, 0 - 9),或者点击Generate SecureToken Shared Secret 按钮来随机生成一个。


    			重要: 你的视频播放网站必须用同样的共享密钥来生成Hash code。最好不要用JavaScript代码来做这个事(会有潜在的风险),应该是服务端生成页面时做。
    		  
  5. 如果你选择了用Hash算法保护所有的流传输协议,继续做如下配置(如果你选择只针对RTMP的保护,可以跳过这一段):

    1. Hash Algorithm的下拉框中选择你需要的算法。



      如果你以前用过针对RTMP的保护,为了继续兼容,你可以在Use TEA for RTMP token security的复选框中打勾,其它流传输协议依然采用你下拉框中选择的Hash算法。

      为了更安全,你还可以在Include client IP address in hash generation复选框前打勾。这让会导致Wowza在计算Hash时,将客户端IP地址做为计算Hash的一部分。
      注意:这个功能要谨慎使用,因为网络情况会比较复杂,比如Nat,比如IP地址变化等。这会导致你在客户端得到的IP地址和WOwza检测到的IP地址不符,从而导致Hash匹配失败,最终会话连接被拒绝。
    2. Hash Query Parameter Prefix的输入框中输入一个query parameter前缀,或者用默认的(wowzatoken).



      这个前缀的有效字符范围是 (a - z, A - Z, 0 - 9), 百分号(%), 点(.), 下划线(_), 波浪符(~), 以及横杠(-).

  6. 点击Save.
Wowza端关于SecureToken的配置就完成了。在播放页面生成时(返回给浏览器之前),你的视频网站端也必须用同样的共享密钥来生成客户端的Hash

SecureToken的URL查询参数


SecureToken 的URL查询参数是客户端请求Wowza流服务时,在URL中发送给Wowza的一些附加参数。Wowza必须能够识别URL中的这些参数,这样才能在计算Hash时将其加入进去,因此这些参数必须以SecureToken query parameter 前缀为开始。 这里的例子使用wowzatoken为前缀。

hash

(必须的) 在客户端生成Hash时的字符串必须是 URL-safe Base64-encoded格式的。URL-safe Base64 encoding 将用'-'替换'+',用'_'替换'/'。
也就是说,你要先计算Hash值后,再对这个Hash值做Base64编码,然后对这个Base64编码后的字符串做一个字符替换(用'-'替换'+',用'_'替换'/')。
例如: wowzatokenhash=VSNlS5S2Na5KxwwiVLXIcHwC90CF2lHdmCm9v_8Bh0o=

starttime

(可选) 这个时间(UTC seconds格式) 是SecureToken 播放安全功能的启用时间。如果URL中没有带这个时间或者这个时间的值为0,则SecureToken 播放安全功能立即启用。 在这个时间之前发生的播放连接都将被拒绝。

例如: wowzatokenstarttime=1405036800 (11 July 2014 00:00:00 GMT)

endtime

(可选) 这个时间(UTC seconds格式) 是SecureToken 播放安全功能停止的时间。如果URL中没有带这个时间或者这个时间的值为0, 则SecureToken 播放安全功能一直保持启用状态。SecureToken 不会过期, 但这样是不太安全的。在这个时间之后发生的Player连接将被拒绝。

例如: wowzatokenendtime=1405123200 (12 July 2014 00:00:00 GMT, 24 hours from the starttime.)

注意: 我们推荐你设置一个endtime时间,在大多数场景这样会更安全;然而有时候你希望SecureToken 永不过期。所以,你要根据你的需求来考虑使用需要这个参数。

自定义参数

你可以添加一些自定义参数,用于Hash的计算,这些参数可以是key/value对或者单独的值。

例子1 (key/value pair): wowzatokenCustomParameter=myValue

例子2 (key value): wowzatokenCustomParameter

举例说明, 你可以添加一个用户的唯一标识,确保每一个用户有一个唯一的Hash值。

例子: wowzatokenCustomerHash=N4asd45ESSdkLHfa3qwer_0923zdghMLOE_seda375oz=

Hash的生成


这里介绍了生成Hash的规则,你的客户端(相对于Wowza而言)必须遵循这个规则,才能确保你计算的Hash和Wowza计算的Hash是一直的。

重要:你最好是在服务端计算Hash然后返回给客户端,而不是在客户端(比如Javascript)生成Hash,因为那样会暴露代码并导致一些安全隐患。
  1. 计算Hash的字符串最开头是你的流内容路径(直播流名字或VOD文件名)。内容路径从Wowza的应用名开始(不要用'/'开始)并跟上完整的流名字。 注意不要在流名字后加上HTTP请求的类型关键字符(例如,/manifest.m3u8, /media.ts, /Manifest, /manifest.f4v等等)。 请参考下面的例子

  2. 在上一步的内容路径后面加上'?'这个分隔符将内容路径从SecureToken 查询参数中区分出来。

  3. 在上一步的"?"后面加上SecureToken 查询参数、共享密钥以及客户端IP地址(如果前面选择了在Hash中加入IP地址的功能)。这些参数都必须按阿拉伯字母顺序来排列,并以'&'分隔开。


例子

下面的例子使用SHA-256 计算hash

HLS 的例子

这个例子非常简单,就是播放wowza自带的sample.mp4文件。 使用的前缀是一个自定义的值。 在计算Hash的字符串中包含了一个自定义参数,以及客户端IP地址、起始时间和结束时间。

原始的播放URL: http://192.168.1.1:1935/vod/sample.mp4/playlist.m3u8
内容路径: vod/sample.mp4
自定义的SecureToken 前缀: myTokenPrefix
自定义的 SecureToken 查询参数: myTokenPrefixCustomParameter=abcdef
Token 的开始时间: myTokenPrefixstarttime=1395230400
Token 的结束时间: myTokenPrefixendtime=1500000000

下面是用于计算Hash的字符串的各个组成部分(下面的列表并没有按阿拉伯字母顺序来):

  • myTokenPrefixstarttime=1395230400
  • myTokenPrefixendtime=1500000000
  • myTokenPrefixCustomParameter=abcdef
  • mySharedSecret
  • 192.168.1.2

用于计算Hash的字符串(按阿拉伯字符顺序排列):


vod/sample.mp4?192.168.1.2&mySharedSecret&myTokenPrefixCustomParameter=abcdef&myTokenPrefixendtime=1500000000&myTokenPrefixstarttime=1395230400


最终发送给Wowza的HLS URL:

http://192.168.1.1:1935/vod/sample.mp4/playlist.m3u8?myTokenPrefixstarttime=1395230400&myTokenPrefixendtime=1500000000&myTokenPrefixCustomParameter=abcdef&myTokenPrefixhash=TgJft5hsjKyC5Rem_EoUNP7xZvxbqVPhhd0GxIcA2oo=

RTSP的例子

还是以播放sample.mp4文件为例。 前缀用的是默认的设置(wowzatoken),在计算Hash的字符串中包含了一个自定义参数和SecureToken的结束时间。 没有带客户端IP地址,也没有带SecureToken的开始时间(SecureToken 播放安全立即生效)。

原始的播放 URL: rtsp://192.168.1.1:1935/vod/sample.mp4
内容路径: vod/_myInstance_/sample.mp4
自定义的 SecureToken 查询参数: wowzatokenCustomParameter=abcdef
Token的结束时间: wowzatokenendtime=1500000000

用于计算Hash的字符串的各个组成部分(下面的列表并没有按阿拉伯字母顺序来):

  • wowzatokenendtime=1500000000
  • wowzatokenCustomParameter=abcdef
  • xyzSharedSecret


用于计算Hash的字符串(按阿拉伯字母顺序排列):

vod/_myInstance_/sample.mp4?wowzatokenCustomParameter=abcdef&wowzatokenendtime=1500000000&xyzSharedSecret


最终发送给Wowza的RTSP URL:

rtsp://10.0.2.31:1935/vod/_myInstance_/sample.mp4?wowzatokenendtime=1500000000&wowzatokenCustomParameter=abcdef&wowzatokenhash=kJ591xB2lT-X0OA9UdoRx61uwp6A_IoSc_jCx_9h1l8=

Flash 播放器端的SecureToken设置


如果你选择了针对所有流传输协议统一的hash算法,你必须将SecureToken 查询参数传递给Flash 播放器,这样它才能被发送给Wowza Streaming Engine。 例如,以JW Player 6.8为例,可以按下面来配置JW Player:
jwplayer("player").setup({
    autostart: false,
    file: "<url>",
    rtmp: {	bufferlength: 5	},
    width: "600",
    height: "337",	
});
这里的<url> 就是: rtmp://[wowza-ip-address]:1935/vod/sample.mp4?wowzatokenendtime=1500000000&wowzatokenCustomParameter=abcdef&wowzatokenhash=kJ591xB2lT-X0OA9UdoRx61uwp6A_IoSc_jCx_9h1l8=

如果你选择针对RTMP协议用Tiny Encryption Algorithm (TEA)算法,你必须用ActionScript代码来相应SecureToken challenge。 要了解更多细节,请参考如何用SecureToken对RTMP流进行保护?

SecureToken 相关参数参考


下面介绍了一些SecureToken功能相关的参数配置,这些参数可以配置在Wowza应用的属性中。你可以在这个应用的application.xml文件中配置,也可以用Wowza Streaming Engine Manager管理页面来配置。

注意:
  • 配置完成后,要重启Wowza,才能让配置生效。

securitySecureTokenVersion

选择SecureToken 的版本。
<Property>
    <Name>securitySecureTokenVersion</Name>
    <Value>2</Value>
    <Type>Integer</Type>
</Property>
有效的数值是1 或者 2:

  • 1 - 版本1. 这个版本在针对RTMP协议时,采用Tiny Encryption Algorithm (TEA)算法。

  • 2 - 版本2. 这个版本针对所有流传输协议采用统一的Hash算法。

securitySecureTokenSharedSecret

设置共享密钥,有效字符包括(a - z, A - Z, 0 - 9).
<Property>
    <Name>securitySecureTokenSharedSecret</Name>
    <Value>sharedsecret</Value>
    <Type>String</Type>
</Property>


securitySecureTokenUseTEAForRTMP

securitySecureTokenVersion 被设置为 2时,如果下面这个参数被设置为true就会针对RTMP协议单独使用TEA算法。
<Property>
    <Name>securitySecureTokenUseTEAForRTMP</Name>
    <Value>false</Value>
    <Type>Boolean</Type>
</Property>

securitySecureTokenHashAlgorithm

securitySecureTokenVersion 被设置为 2时,下面这个参数设置了具体的Hash算法。
<Property>
    <Name>securitySecureTokenHashAlgorithm</Name>
    <Value>SHA-256</Value>
    <Type>String</Type>
</Property>
这个Value的有效值包括: SHA-256, SHA-384, 或 SHA-512[/S]

securitySecureTokenQueryParametersPrefix

securitySecureTokenVersion被设置为2, 下面这个参数设置了针对所有SecureToken 查询参数的前缀。
<Property>
    <Name>securitySecureTokenQueryParametersPrefix</Name>
    <Value>wowzatoken</Value>
    <Type>String</Type>
</Property>
这个Value的有效字母包括(a - z, A - Z, 0 - 9)、百分号 (%)、点(.)、下划线(_)、波浪符(~) 以及横杠(-)[/B]

securityDebugLogRejections

下面这个参数适用于所有的securitySecureTokenVersion。将这个参数设置为true会将所有拒绝连接的消息记录到日志中。
<Property>
    <Name>securityDebugLogRejections</Name>
    <Value>false</Value>
    <Type>Boolean</Type>
</Property>
注意:要在Streaming Engine Manager管理界面中添加这个参数,请参考添加Log日志.

securityDebugLogDetails

下面的参数适用于所有的securitySecureTokenVersion。当设置为true时可以让SecureToken模块输出更详细的debug日志。
<Property>
    <Name>securityDebugLogDetails</Name>
    <Value>false</Value>
    <Type>Boolean</Type>
</Property>
注意:
  • 要在Streaming Engine Manager管理界面中添加这个参数,请参考添加Log日志.

  • 打开了这个日志后,会导致Wowza生成很大的日志文件.

SecureToken parameters encoded into manifest and media responses


在使用Apple HLS, Adobe HDS, and MPEG-DASH 协议时,这些协议会将SecureToken 查询参数返回在http响应的Submanifest中。

  • 这些参数是在前面的请求中,Wowza接收到的参数。

  • 这些参数是Base64编码后的,'_'将被替换为'!'。

  • 这些参数在返回时位于_tk后面。

Apple HLS 的例子

请求: http://192.168.1.1:1935/vod/sample.mp4/playlist.m3u8?myTokenPrefixstarttime=1395230400&myTokenPrefixendtime=1500000000&myTokenPrefixCustomP arameter=abcdef&myTokenPrefixhash=o4ICgenL8-KU2uktN6XvrN8kCFlXBl7k65PorS2odRk=

响应中的Submanifest:
chunklist_w1955037621_tkd293emF0b2tlbnN0YXJ0dGltZT0xMzk1MjMwNDAwJndvd3phdG9rZW5lbmR0aW1lPTE1MDAwMDAwMDAmd293emF0b2tlbmhhc2g9 eG0xQW1INUtRWDl6ZVdzTEQ4NzJmc1pCZFptMXloSlFuUGxSN25wclVwQT0=.m3u8

注意: Smooth Streaming 协议返回的Submanifest是正常的SecureToken 查询参数,不是Base64编码的。

在log日志中会显示相关配置参数


当Wowza应用启动后,在[install-dir]/logs/wowzastreamingengine_access.log文件中你会看到下面的参数会显示出来:

假设SecureToken功能被设置为所有协议使用统一的Hash算法(securitySecureTokenVersion被设置为2):

INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: using SecureToken Version 2, play security enabled for RTMP, RTSP, HLS, HDS, SmoothStreaming and Dash protocols
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: using SHA-256 for play security
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: securitySecureTokenIncludeClientIPInHash: true
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: SecureToken query parameters prefix is wowzatoken
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: SecureToken token start time query parameter is wowzatokenstarttime
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: SecureToken token end time query parameter is wowzatokenendtime
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: SecureToken token hash query parameter is wowzatokenhash

假设SecureToken功能被设置为所有协议使用统一的Hash算法(securitySecureTokenVersion被设置为2) 但又设置了针对RTMP协议使用Tiny Encryption Algorithm (TEA)(securitySecureTokenUseTEAForRTMP 被设置为true):

INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: using TEA for RTMP play security

如果SecureToken 设置为仅针对RTMP协议,并且使用TEA(securitySecureTokenVersion被设置为11):

INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: using SecureToken Version 1, play security enabled for RTMP only

假设SecureToken功能被关闭(securitySecureTokenVersion 没有被设置):

INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: securitySecureTokenVersion property is missing, using SecureToken Version 1, play security enabled for RTMP only
INFO server comment - ModuleCoreSecurity.onAppStart[security-vod/_definst_]: Play: using SecureToken Version 1, play security enabled for RTMP only

故障排查


添加log日志

你可以打开securityDebugLogRejectionssecurityDebugLogDetails 参数,这样可以在日志中打印更多的日志,帮助我们定位一些配置上的问题。 要在Wowza Streaming Engine Manager管理界面上添加这些参数,你必须将它们添加在应用的自定义参数部分。

下面是在Add Custom Property对话框中要输入的信息:

securityDebugLogRejections
Path
Name
Type
Value
Root/Application securityDebugLogRejections Boolean true

securityDebugLogDetails
Path
Name
Type
Value
Root/Application securityDebugLogDetails Boolean true

Hash值不匹配时拒绝Session会话连接

下面是因为客户端发来的Hash和Wowza自己计算的Hash不匹配时,Http session 被拒绝的日志例子:

注意: The securityDebugLogDetails 参数必须启用。
INFO application app-start _definst_ security-vod/_definst_
INFO server comment - ModuleCoreSecurity.onStreamCreate[security-vod/_definst_]: Client is null. No Secure Token check.
INFO cupertino connect 1549778894 -
INFO stream create sample.mp4 -
INFO server comment - ModuleCoreSecurity.onHTTPSessionCreate[security-vod/_definst_/sample.mp4]: All security checks passed.
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:current time stamp: 1403636858
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:sessionId: 1549778894
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:hashReceived: 1Rw3ZGgn0-peLuu39yqEOQolqj_xWRJ1U3na2emyL8U=
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:creating httpToken for SessonId:1549778894 uri:/security-vod/sample.mp4/playlist.m3u8?wowzatokenstarttime=1395230400&wowzatokenendtime=1500000000&wowzatokenhash=1Rw3ZGgn0-peLuu39yqEOQolqj_xWRJ1U3na2emyL8U=
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:client IP: 10.0.2.31
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:hashCalculated: IF0Ai8BCqLPf-fEpIbJ5HT6xUDWa6o1W43FLTRfQZRU=
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:string hashed: security-vod/sample.mp4?sharedsecret&wowzatokenendtime=1500000000&wowzatokenstarttime=1395230400
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:token start time stamp: 1395230400
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:token end time stamp: 1500000000
INFO server comment - [security-vod/_definst_]SecureTokenDef:Hash 1Rw3ZGgn0-peLuu39yqEOQolqj_xWRJ1U3na2emyL8U=, doesn't match hash calculated, IF0Ai8BCqLPf-fEpIbJ5HT6xUDWa6o1W43FLTRfQZRU=
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:client IP: 10.0.2.31
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:hashCalculated: 1FGT5uuUaVQPFBB-NIawz41I0pAtjQbrezyMGlXO3aE=
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:string hashed: security-vod/sample.mp4?sharedsecret&wowzatokenendtime=1500000000&wowzatokenstarttime=1395230400
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:token start time stamp: 1395230400
INFO server comment - [security-vod/_definst_]ModuleCoreSecurity:token end time stamp: 1500000000
INFO server comment - [security-vod/_definst_]SecureTokenDef:Hash 1Rw3ZGgn0-peLuu39yqEOQolqj_xWRJ1U3na2emyL8U=, doesn't match hash calculated, 1FGT5uuUaVQPFBB-NIawz41I0pAtjQbrezyMGlXO3aE=
WARN server comment - HTTPStreamerAdapterCupertinoStreamer.onPlaylist[security-vod/sample.mp4/playlist.m3u8?wowzatokenstarttime=1395230400&wowzatokenendtime=1500000000&wowzatokenhash=1Rw3ZGgn0-peLuu39yqEOQolqj_xWRJ1U3na2emyL8U=]: Session not accepted[1549778894]
INFO stream destroy sample.mp4 -
INFO cupertino disconnect 1549778894 -

第一个红色高亮的log显示了用于计算Hash的字符串,这个字符串的各个组成部分是按阿拉伯字母顺序排列的,并且必须和客户端计算Hash时的字符串保持一致。

第二个红色高亮的log显示了Wowza生成的Hash和接收到的来自客户端的Hash,并提示它们两者并不匹配。

下面是Wowza 官方给出的一段PHP代码的例子,它展示了应该如何生成播放URL,如下:

<?php
$clientIP = null; // provide client IP optionally
$host = "[WOWZA-HOST]"; // your ip/host
$url= "rtmp://".$host.":1935/";   // or "http://".$host.":1935/";
$stream = "vod/_definst_/mp4:sample.mp4"; // your stream
$start = time();
$end = strtotime("+30 minutes");
$secret = "abcde";
$tokenName = "wowzatoken";
$hash = "";
if(is_null($clientIP)){
  $hash = hash('sha384', $stream."?".$secret."&{$tokenName}endtime=".$end."&{$tokenName}starttime=".$start, true); // generate the hash string
}
else{
  $hash = hash('sha384', $stream."?".$clientIP."&".$secret."&{$tokenName}endtime=".$end."&{$tokenName}starttime=".$start, true); // generate the hash string
}
$base64Hash = strtr(base64_encode($hash), '+/', '-_');
// $params = array("{$tokenName}starttime=".$start, "{$tokenName}endtime=".$end, "{$tokenName}hash=".$base64Hash);
$params = array("{$tokenName}starttime=".$start, "{$tokenName}endtime=".$end, "{$tokenName}hash=".$base64Hash);
if(!is_null($clientIP)){
  $params[] = $clientIP;
}
sort($params);
$playbackURL = $url.$stream."/playlist.m3u8?";
if(preg_match("/(rtmp)/",$url)){
  $playbackURL = $url.$stream."?";
}
foreach($params as $entry){
  $playbackURL.= $entry."&";
}
$playbackURL = preg_replace("/(\&)$/","", $playbackURL);
// echo "$playbackURL"; // DEBUG - show fully formed URL
?>