网络视频(Web 视频)是指利用 HTML5 技术在浏览器中播放的视频,这类视频资源通常可以被随意下载,某些行业(比如教培行业)如果希望保护自己的视频资源不被下载,就需要对视频做防盗链处理。
防盗链需要着重加强两个方面的安全性:网络传输和客户端。
网络传输安全
网络传输层面能做的不多,HTTPS
是必要的,除此之外的防护措施效果也有限。
验证 Referer
防盗链最常规的手段是验证Referer
,而伪造Referer
几乎零成本,所以它只防君子不防小人,没用。
请求防重放
盗链可以理解成一种对静态资源的“重放攻击”,所以可以用应对重放攻击的思路来改造静态资源请求,通过一个动态接口返回静态资源,并且加入变量让动态请求短时间内失效,比如随机数、时间戳、流水号等等。
这种方式可以做到让链接地址没有复用价值,但攻击者如果脚本化还是可能在有限时间内下载到文件本身。而且这种方案会明显提升服务端的性能压力,因为静态资源的请求量往往比较大,尤其是视频通常还要处理成 m3u8 格式的视频切片,请求量会剧增。
请求权限校验
动态接口可以叠加上权限校验,这也是常见的业务需求,仅授权用户可见。
虽然作为一种防盗手段来说这约等于没有,因为请求信息都能在 chrome 里拿到,在 postman 里重放请求就行了。但这种手段却可以有效的防住一大批视频下载浏览器插件,因为大部分下载插件都是直接请求 url,如果授权信息放在header
里那么它们就无法通过权限验证。
客户端安全
站在客户端的角度看网络传输会有一种后院着火的感觉。
BS 架构中的浏览器在设计上就不需要为数据安全负责,所有拿到的东西默认都是经过服务端允许的,因此浏览器中的图片、音视频、附件甚至代码都可以直接右键下载或查看。想要在浏览器端保护资源安全,除了对数据加密别无他法。
HLS 加密传输
目前的网络视频基本上都是基于 HLS 协议的流媒体格式,HLS 协议本身就支持对切片视频做加密,不过 HLS 的加密算法是公开的,HLS 协议的视频加解密有两个要素,分别是 key 和视频切片,只要具备这两者就可以按约定的加密算法(AES128)对其解密,而 key 和切片又都在 m3u8 文件中明文传输,因此任意支持 HLS 协议的播放器或视频处理类库都可以播放所谓的加密 m3u8。
而要下载加密过的 m3u8 视频,只要通过 m3u8 文件拿到 key 文件和视频切片文件,然后本地一句代码就可以拿到完整视频:
1 | ffmpeg -allowed_extensions ALL -i video.m3u8 -c copy out.mp4 |
基于 HLS 的私有加密
为了提高安全性,可以对 key 或视频文件二者中任何一个做私有加密,使得即使下载了所有文件也无法通过常规播放器播直接放该视频,因为加密方法是私有的,解密方法也只有开发者自己知道。想要正常播放需要定制前端播放器,让视频流进入 HLS 标准解密流程前,先用配套的解密函数将内容解密,从而顺利播放。
这种方式可以防住所有市面上现成的下载工具(除非有人专门针对你家开发一款工具),和大部分非专业的攻击者,如果商业价值不是特别大,这种方案的性价比是最高的。
有很多方法可以破解这种加密方案,比如直接读前端代码找解密方法,即便代码混淆了,只要花足够的时间,总是能被找出来的。但这是最笨的方法,更轻松的破解思路是,无论视频怎么加密,最终总归要把视频流解密出来送给播放器,我们只要守在播放器的门口就可以等着视频送上门。所以问题变成了找到前端播放器获取视频流的方法,如果前端播放器是基于开源项目改的(可以通过 DOM 结构来识别),比如videojs,那么阅读其源码就只可以知道在播放 HLS 视频时有一个关键方法appendBuffer(bytes)
,这个方法的参数就是解密后的视频流,在整个源码中搜索这个方法就相对容易多了,找到后通过替换脚本可以直接拿到这个视频流,JS 利用 Blob 对象实现本地下载。
基于上述守株待兔的思路,更彻底的方式是直接 hook 浏览器,因为前端播放器可以千变万化,但最终都会来到最底层的浏览器播放器,不幸的是 chrome 内核也是开源的,找到这最后一扇门,编译一个自己的浏览器,理论上可以秒杀任何网络视频加密手段。因此有些商业加密方案一定要配套浏览器,或者干脆不支持 HTML5 只支持原生 Android 和 IOS,相当于将风险瓶颈提高到了客户端源码安全这个高度。至此整个视频从网络传输到客户端播放才算完整的被围了一圈铁桶,要攻破这铁桶的任何一块都不会轻而易举。
综上所述,虽然基于 HLS 的私有加密仍然算不上很安全,但也是性价比很高的防盗方案了,即便不配套专用浏览器,想通过现成的工具盗取视频已然不可能,对于有专业技能的人也需要花费一定时间才能破解,这基本上就能拦住一大批攻击者。如果自身商业价值不是特别大,应该就够用了。
防录屏
水印
在录屏面前任何技术手段都没有意义,我们能做的顶多是加个水印,起到一点聊胜于无的“宣示主权”或“威慑”作用。
技术上水印有两种加法,可以前端在播放界面上覆盖一个水印层,也可以直接加在视频内容中。
前端水印实现简单,而且可以直接展示用户信息和时间戳等,威慑力更强。但破解也很简单,只要会百度破解难度就等于零。
后端水印实际上是往视频中混了一路视频流,如果源文件被下载到也很容易去掉水印拿到“无码”版,但我们这里讨论水印的前提是视频文件无法下载,否则谁还录屏,因此水印直接加到视频中更可靠一些。但给视频加水印需要一定的转码时间,因此水印信息只能是静态的,无法在水印中体现用户信息和时间之类的动态信息,威慑力为零,只能起到一点“宣示主权”的作用,使视频无法用于公开的商业活动。
水印的位置也有几种不同的形式,除了固定位置外,还有跑马灯、动态位置、随机位置等,主要目的都是为了提高去水印的难度,巩固仅剩的那一点“宣誓主权”作用。
其他
录屏虽然防不住,但可以用一些撒泼打滚的方法降低录制视频的质量,比如不定时弹出个问答题,或者一段时间没有操作就弹出个人机验证,这些方法从性价比上看都很差,因为面对攻击者这些前端小伎俩很容易破解,另一方面对真正的用户却造成了实实在在的干扰,属于伤敌一千自损八百。
总结
- 网络请求使用支持权限校验和时效性的动态接口
- 基于 HLS 协议对 key 或 ts 文件私有加密,需要定制前端播放器
- 加水印,前端水印威慑力强,视频水印可靠性高
- 其他前端措施都是花里胡哨意义不大
最后,试图用孱弱的浏览器脚本(JS)来封堵浏览器端的“安全漏洞”,总的来说会是一场不限时间的“捉迷藏”游戏,结局必定会以失败告终。所以我们在这场游戏中的任务不是赢,而是在失败之前让进攻方放弃。
文中介绍的加密方法已经整合到cutting-mat-widgets项目中,只要配合后端将 m3u8 中的 key 加密,并约定实现前端解密算法,就可以简单的实现视频加密;并且,也整合了前端水印功能,支持随机位置和水印破坏检测。
- GIthub: https://github.com/cutting-mat/cutting-mat-widgets
- 文档:https://cutting-mat.github.io/cutting-mat-widgets/#/business-video
参考
前端路上原创技术文章,转载请注明出处:https://refined-x.com/2022/05/26/网络视频的防盗与破解/
不甘平庸的你,快来跟我一起充电吧,关注看风景,获取更多精彩内容。