需求背景
- 目前很多业务对音视频版权及保护有更高的诉求
- referer防盗链方案安全系数不满足个别业务的要求
解决方案
- 业界针对资源防盗问题,一般的做法:
方式 | 实现原理 | 优缺点 |
---|---|---|
referer防盗链 | 在域名层面配置referer白名单,当用户向cdn服务器请求资源文件时,cdn首先会获取http头部的referer字段,检查访客的来源,如果在白名单内,则返回资源,否则返回403拒绝请求。 参考文档:developer.qiniu.com//fusion/kb/… |
优点: 1、实现非常简单,只需要在cdn域名层面配置referer白名单即可; 2、业务端和存储这边不用做任何代码上的调整。 缺点: 1、安全性较低,可以通过构造referer的方式获取到资源,易于破解。 |
时间戳防盗链 | 时间戳防盗链目的是使资源的url具有一定的“时效性”,URL会携带过期时间参数,不能随意修改。通过md5算法,将一些信息进行加密得到签名,加入到URL,并在CDN节点或OSS层进行验证。 参考文档:developer.qiniu.com/fusion/kb/1… |
优点: 1、实现也非常简单,在cdn服务商配置密钥,然后业务服务端保存密钥,生成链接时对URL进行签名; 2、鉴权部分都交给cdn节点处理; 3、安全性较高。 缺点: 1、这种方式只具备防盗链效果,并不能防止下载,就是一种临时授权访问资源的技术。 |
前端将视频内容切分,将分片内容的播放地址转换为blob的形式 | 目前很多视频网站,如b站、爱奇艺等,我们用f12进去,看到video标签内的视频地址都是“blob:XXX”的形式以屏蔽真实的视频链接。 blob其实就是可以当作文件使用的二进制数据,只需要生成一个指向blob的地址,就可以在video标签中进行播放。 参考原文:juejin.cn/post/684490… |
优点: 1、屏蔽真实链接,blob链接无法被下载; 2、前端有一些开源的实现,可以做为参考使用。 缺点: 1、可以通过抓包的形式获取到下载地址。 思考:是否可以在服务器对链接进行加密,然后js解密,再进行链接转换。 |
URL加密 | 业务服务器向前端返回的是加密后的URL,前端修改video标签库,在播放时进行解密。 | 优点:前端屏蔽真实链接,不能直接拿到。 缺点:无法防止抓包等形式获取下载地址。(因为最终发起请求时还是解密后的真实URL) |
回源鉴权 | 在cdn层面配置鉴权服务器,用户请求到达cdn节点时,cdn节点会将用户的请求原封不动的转发给鉴权服务器。鉴权服务器可以根据请求头中的参数给出鉴权结果。 参考原文:developer.qiniu.com/fusion/manu… |
优点: 1、根据业务自定义鉴权逻辑,安全系数中等; 2、在cdn层面进行配置,灵活性高。 缺点: 1、需要自己实现和搭建鉴权服务器; 2、业务量大的话对鉴权服务器性能要求较高。 |
对资源内容进行加密 | 简单来说,就是将mp4视频转成m3u8,会对视频进行切片,切分成多个ts文件,对分片进行加密。使用自己实现对播放器sdk,获取视频密钥,解密播放。 对资源内容进行加密,别人即使下载了资源,没有密钥也无法播放视频。 |
优点: 1、安全系数高,破解难度大; 2、对于自研媒体服务有一定的技术积累。 缺点: 1、存储成本增加(加密后可以考虑把原文件删除); 2、需要考虑机器成本和网络带宽成本。 |
总结: 在资源url层面进行的防护,总能通过各种各样的手段(抓包、嗅探工具等)拿到真实的播放地址,安全性比较低,这些只能作为辅助手段,在某种程度上可以增加不法分子破解的难度,可以根据业务需求评估这种安全系数是否可以满足。如果业务对资源的安全系数要求很高,期望无论用户是否合法,都只能在允许的地方进行资源观看,即使能够下载下来,也无法进行播放。这种的话,就必须要对资源内容上进行加密。
加密服务设计
知识背景
- HLS 即 HTTP Live Streaming 是由 Apple 提出的基于 HTTP 的流媒体传输协议。它将一整个音频、视频流切割成可由 HTTP 下载的一个个小的音视频流,并生成一个 M3U8 播放列表,客户端只需要获取资源的 M3U8 播放列表即可播放音视频。
- m3u8其实就是一个文本文件,里面记录的是音视频分片的播放列表。
- 如果对每个分片进行加密后,m3u8文件会多了以下内容:method代表的是使用aes-128加密,URI是指定密钥的路径(这个URL我们可以在服务端部署一个密钥管理服务,开放一个密钥获取的接口)
命令构建
- 加密功能是基于ffmpeg工具进行封装的
音视频切片
- 命令解释:将音视频按2s时长进行切片,输出m3u8文件
ffmpeg -y -i test.mp4 -c:a aac -c:v h264 -hls_time 2 -hls_segment_filename "test-%d.ts" test.m3u8
复制代码
加密分片
- 命令解释:对每个分片进行加密,加密信息放在key.txt上
ffmpeg -y -i test.mp4 -c:a copy -c:v copy -hls_time 2 -hls_segment_filename "test-%d.ts" -hls_key_info_file key.txt test.m3u8
复制代码
加密架构
- 加密过程和解密过程是独立的,业务方将需要加密的音视频资源请求音视频加密服务进行加密,整个过程是异步处理的,完成后会将结果文件存储到oss上,并回调通知业务。
- 媒体处理服务作为公司底层的基础服务,没有业务属性,不具备用户合法性鉴权的能力。所以该服务只允许内网调用,所有调用请求必须经过业务服务器发起,业务服务端自己做好鉴权即可。
1、加密流程
- 将文件下载到服务器本地
- 生成一个随机的aes128字符串密钥
- 使用ffmpeg对文件进行切片加密
- 将加密后的视频分片以及m3u8文件上传到存储服务商
- 将密钥保存到数据库(搭建自己的密钥管理服务)
2、播放器解密流程
- 首先获取m3u8的下载链接以及资源访问令牌
- 访问令牌为一次性token
- 安全参考:developer.aliyun.com/article/752…
- 发送请求向服务商获取m3u8文件
- 从m3u8文件获取到密钥的接口地址:keyUrl
- 携带访问令牌访问keyUrl获取密钥
- 获取视频切片内容
- 使用密钥对视频进行解密播放
对于资源访问令牌,只有当业务服务端验证过当客户端,才能请求KMS服务。
3、KMS密钥服务搭建
- 在加密过程,业务调用媒体服务的加密接口进行异步处理,媒体服务处理完成后会回调业务一个新的fileKey(m3u8文件)
- 在解密过程:
- 播放器请求业务端获取下载链接以及访问令牌
(为什么这里不是前端直接请求媒体服务呢?因为业务鉴权需要交给业务服务器来做,基础服务不做鉴权,不要试图在前端直接请求我们的接口)
- 拿到URL和令牌之后,通过URL可以获取到m3u8文件
- 读取m3u8文件中的密钥URL,在密钥URL后面拼接访问令牌,就可以获取到解密密钥啦
- 获取到解密密钥,浏览器就能正常播放视频
- 播放器请求业务端获取下载链接以及访问令牌
问题汇总
1、ios端不兼容此解密流程
- 问题描述:ios不能定制化请求m3u8的keyurl,即不能获取完token之后,将token拼接上去获取密钥。
- 解决办法:
- iOS端使用原链接进行播放,即只使用referer防盗链端链接
- 这种方式会使iOS端的文件有安全隐患
- 该问题如果不解决,其他业务接进来也会遇到同样的情况
- 在cdn侧配置m3u8改写:help.aliyun.com/document_de…
- 比如正常的播放地址为vod.demo.com/test.m3u8, 当拼接携带token参数后为vod.demo.com/test.m3u8?t…,阿里CDN会动态修改m3u8文件中的解密URI(EXT-X-KEY:METHOD=AES-128,URI="decrypt.demo.com?Ciphertext=aabbccddeeff&MediaId=fbbf98691ea44b7c82dd75c5bc8b9271")
- iOS端使用原链接进行播放,即只使用referer防盗链端链接
2、我调用接口时传入参数是分片2s,为什么结果文件的切片时长是不精确的?
- 假设我们视频切片设置参数“-hls_time 2”,希望生成的ts文件时长在2秒左右,但是结果文件很多分片都是不准确的
1)产生的原因:
- ts切割跟视频的GoP(两个关键帧之间的间隔)大小有关,并不是指定2s切出来就2s的ts文件。任何一个播放端都需要获取到完整的GoP才能播放端,所以一个ts文件实际包含的时间是GoP的整数倍。
2)这个问题是否能解决?
- 能,我们既然已经知道了问题的原因是关键帧的间隔不对应,那么只需要在转码的时候,设置好关键帧的间距即可。
ffmpeg -y -i test.mp4 -force_key_frames "expr:gte(t,n_forced*2)" -hls_time 2 -hls_segment_filename "test-%d.ts" -hls_list_size 0 test.m3u8
复制代码
-force_key_frames "expr:gte(t,n_forced*2)"
:每2s打上一个关键帧
3)那是否意味着我们业务就能使用精准切割?
- 不能,最起码暂时不能,因为我们暂时不会开放这个能力。
- 为什么?
- 原因很简单,资源消耗较大,且重要性不大。业务其实不需要太关注每个切片的大小是否精准,业务关心的是我们播放视频的时候是否会造成卡顿。这个其实问题不大,切出来的视频虽然时长会稍微有点偏差。但是通过测试可以发现,上面截图那个剪切不精确的:第1个分片6s,但是文件大小只有114KB;第二个分片是3s,文件是886KB;第3个分片是1s,文件是722KB。从数据可以看出,文件大小并不只跟时长呈正相关。