媒体处理-音视频 HLS 加密服务设计

需求背景

  • 目前很多业务对音视频版权及保护有更高的诉求
  • 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层进行验证。image.png
参考文档: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节点会将用户的请求原封不动的转发给鉴权服务器。鉴权服务器可以根据请求头中的参数给出鉴权结果。image.png

参考原文: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其实就是一个文本文件,里面记录的是音视频分片的播放列表。
    • image.png
  • 如果对每个分片进行加密后,m3u8文件会多了以下内容:method代表的是使用aes-128加密,URI是指定密钥的路径(这个URL我们可以在服务端部署一个密钥管理服务,开放一个密钥获取的接口)
    • image.png

命令构建

  • 加密功能是基于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
复制代码

加密架构

image.png

  • 加密过程和解密过程是独立的,业务方将需要加密的音视频资源请求音视频加密服务进行加密,整个过程是异步处理的,完成后会将结果文件存储到oss上,并回调通知业务。
  • 媒体处理服务作为公司底层的基础服务,没有业务属性,不具备用户合法性鉴权的能力。所以该服务只允许内网调用,所有调用请求必须经过业务服务器发起,业务服务端自己做好鉴权即可。

1、加密流程

  • 将文件下载到服务器本地
  • 生成一个随机的aes128字符串密钥
  • 使用ffmpeg对文件进行切片加密
  • 将加密后的视频分片以及m3u8文件上传到存储服务商
  • 将密钥保存到数据库(搭建自己的密钥管理服务)

image.png

2、播放器解密流程

  • 首先获取m3u8的下载链接以及资源访问令牌
  • 发送请求向服务商获取m3u8文件
  • 从m3u8文件获取到密钥的接口地址:keyUrl
  • 携带访问令牌访问keyUrl获取密钥
  • 获取视频切片内容
  • 使用密钥对视频进行解密播放

对于资源访问令牌,只有当业务服务端验证过当客户端,才能请求KMS服务。 image.png

3、KMS密钥服务搭建

  • 在加密过程,业务调用媒体服务的加密接口进行异步处理,媒体服务处理完成后会回调业务一个新的fileKey(m3u8文件)
  • 在解密过程:
    • 播放器请求业务端获取下载链接以及访问令牌(为什么这里不是前端直接请求媒体服务呢?因为业务鉴权需要交给业务服务器来做,基础服务不做鉴权,不要试图在前端直接请求我们的接口)
    • 拿到URL和令牌之后,通过URL可以获取到m3u8文件
    • 读取m3u8文件中的密钥URL,在密钥URL后面拼接访问令牌,就可以获取到解密密钥啦
    • 获取到解密密钥,浏览器就能正常播放视频

image.png

问题汇总

1、ios端不兼容此解密流程

2、我调用接口时传入参数是分片2s,为什么结果文件的切片时长是不精确的?

  • 假设我们视频切片设置参数“-hls_time 2”,希望生成的ts文件时长在2秒左右,但是结果文件很多分片都是不准确的

image.png

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打上一个关键帧

image.png

3)那是否意味着我们业务就能使用精准切割?

  • 不能,最起码暂时不能,因为我们暂时不会开放这个能力。
  • 为什么?
    • 原因很简单,资源消耗较大,且重要性不大。业务其实不需要太关注每个切片的大小是否精准,业务关心的是我们播放视频的时候是否会造成卡顿。这个其实问题不大,切出来的视频虽然时长会稍微有点偏差。但是通过测试可以发现,上面截图那个剪切不精确的:第1个分片6s,但是文件大小只有114KB;第二个分片是3s,文件是886KB;第3个分片是1s,文件是722KB。从数据可以看出,文件大小并不只跟时长呈正相关。

参考文档

Supongo que te gusta

Origin juejin.im/post/7066670799259697159
Recomendado
Clasificación