基於HLS的多媒體防盜方案調研
基於HLS的多媒體防盜方案調研
為什麼要加密視訊
視訊加密是為了讓要保護的視訊不能輕易被下載,即使下載到了也是加密後的內容,其它人解開加密後的內容需要付出非常大的代價。即便如此,也無法嚴格保護視訊不被錄製。
常見的防盜技術
- 防盜鏈:只能合法的通過系統認證的使用者才能訪問到資源,其實就是資源訪問鑑權。
- 加密視訊:通過對稱加密演算法加密視訊內容,合法使用者獲取到解密視訊的金鑰,並獲取到解密的視訊內容,在客戶端解密播放。
播放方案
根據經驗播放mp3、mp4檔案的時候,H5 video或audio播放器通過設定header中的content-range向流媒體服務部分獲取一段媒體資料,播放和seek一樣,每次獲取資料位元組數可能比較大,視網路狀況不同,等待的時間不同,位元組越大緩衝等待的時間越久。參考大型視訊網站的做法,發現他們的是將視訊檔案切片播放的。也就是將大的視訊檔案分成N小段,比如按Apple推薦標準每10s切成一段。這樣的優勢是開啟視訊載入速度快,另外播放第n段的時候,播放器會下載n+1段,n+2段不會下載,大大緩解伺服器和頻寬的壓力。
因此為了提高播放效能,並且防止資源被盜,我們將音視訊進行切片,並生成金鑰,用金鑰對音視訊資料進行加密。m3u8支援分片,並建立m3u8格式的索引,可用於直播或點播場景。
因此我們採用的ts切片,瀏覽器播放的流媒體傳輸協議是HLS。
- HLS:Apple 推出的基於 HTTP 協議的 MP4 分片傳輸協議,可用於點播和直播場景。每下載一個分片都需要發生一次 HTTP 請求,所以嚴格來說 HLS 不能稱為流媒體傳輸協議。
流媒體加密原理
流媒體傳輸協議是把音視訊流拆分成連續的小塊之後再傳輸。流媒體加密技術的關鍵在於,對每一分配採用對稱加密演算法。服務端加密,通過驗證的使用者才能使用播放器進行解密。解密的過程是通過m3u8播放列表提供的引數,獲取到金鑰key,通key進行解密播放。現有常見的加密技術分為對稱加密和非對稱加密,對稱加解密計算較快,效率較高,適用於流媒體對延時有要求的場景。HLS提供的對稱加密演算法有AES-128等。
我們的方案
我們的目標是使用者只能在我們系統觀看視訊,但是不能下載(盜用)視訊。前文提到為了提高播放效能,我們採用了切片;為了基本的視訊安全,我們利用HLS支援的AES-128對視訊進行加密。這樣做還是不夠的,因為播放器需要通過m3u8播放列表提供的引數向伺服器發起http請求獲取到金鑰,這樣通過抓包或者瀏覽器 F12 network可以看到請求URL和響應體。也就是說能觀看的使用者可以拿到我們加密的key和視訊切片,通過FFmpeg或相關技術應該是可以將切片合成完整視訊的。因此這樣做還不夠安全。我們的方案是將金鑰key進行二次加密,播放器拿到key以後需要先解密一次得到實際的加密金鑰,然後再將金鑰給到播放器播放。這樣即便拿到介面響應的key也不能拿來解密或用於一般播放器播放。
方案及如何保護金鑰
我們的場景是在Web前端也就是瀏覽器播放,必須藉助瀏覽器生態支援的技術,並且沒有開發我們自己的播放器,有的廠商是有生成自己的視訊格式的,需要廠商自己的播放器才能打得開,這樣相比會更安全。但是我們目前只能利用hls.js或者video.js來播放HLS。video.js 使用的是videojs-contrib-hls外掛,據說videojs-contrib-hls使用的hls.js,其實最終使用的還是hls.js。
video.js
video.js 提供了 XHR 攔截器,對獲取key的URI進行替換,這樣的好處是說,系統外使用者拿到m3u8不能直接用其他播放器開啟,但是合法使用者還是能攔截或檢視到替換後訪問的URI。假如m3u8播放列表類似這樣:
處理URI的程式碼片段如下:
<link media="all" rel="stylesheet" href="https://unpkg.com/video.js@7.1.0/dist/video-js.css"> <script src="https://unpkg.com/video.js@7.1.0/dist/video.js"></script> <video-js id="player"> <source src="//video/index.m3u8" type="application/x-mpegURL" /> </video-js> <script> var player = videojs("player"); var keyPrefix = "key://"; var urlTpl = "https://domain.com/path/{key}"; // player.ready player.on("loadstart", function (e) { player.tech().hls.xhr.beforeRequest = function(options) { // required for detecting only the key requests if (!options.uri.startsWith(keyPrefix)) { return; } options.headers = options.headers || {}; optopns.headers["Custom-Header"] = "value"; options.uri = urlTpl.replace("{key}", options.uri.substring(keyPrefix.length)); }; }); </script>
顯然這個方法不能起到理想的防盜效果。
hls.js
HLS只允許將金鑰與播放器可以檢索的內容連結起來,但它沒有指定如何保護金鑰的特定方法。如果需要對內容和金鑰執行訪問控制,我們可以像處理其他想保護的資源一樣,因為播放器通過HTTP連結訪問它。例如,可以使用某種登入令牌來保護金鑰,該令牌將在請求頭中傳遞。不幸的是,hls.js還不支援為請求key配置客戶化請求頭。這裡通常的做法是在配置中傳遞一個loader,基於現有的loader實現自己的載入器,然後將自定義的HTTP頭放入其中,或者對返回的金鑰資料做處理(比如解密)。另外hls.js自定義分片請求的URL,可以參考這篇文章。
我們在hls.js的配置項李找到了對loader的介紹:
(default: standard
XMLHttpRequest
-based URL loader)Override standard URL loader by a custom one. Use composition and wrap internal implementation which could be exported by
Hls.DefaultConfig.loader
. Could be useful for P2P or stubbing (testing).Use this, if you want to overwrite both the fragment and the playlist loader.
Note: If
fLoader
orpLoader
are used, they overwriteloader
!
我們試著通過改寫這個loader方法來滿足我們的業務場景:
var configure = { //MEU8載入器 loader : function() { const loader = new Hls.DefaultConfig.loader(configure); this.abort = () => loader.abort(); this.destroy = () => loader.destroy(); this.load = (context, config, callbacks) => { const { type } = context; const onSuccess = callbacks.onSuccess; callbacks.onSuccess = (response, stats, context1, networkDetails) => { if (type !== "manifest" && context1.url.endsWith(".key")) { console.log(context1.url) // 這裡對返回的金鑰資料進行處理 // response.data = dealWithKeyData(response.data)); } onSuccess(response, stats, context, networkDetails); }; loader.load(context, config, callbacks); }; } }; if(Hls.isSupported()) { var hls = new Hls(configure); hls.loadSource(videoSrcInHls); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED,function() { video.play(); }); } else { addSourceToVideo(video, videoSrcInMp4, 'video/mp4'); video.play(); }
金鑰的其他保護
m3u8的播放列表以上面截圖為例,請注意#EXT-X-KEY這個引數提供了加密金鑰的URI。播放器將從該位置檢索金鑰以解密媒體段。為了防止金鑰被竊聽,應該通過HTTPS對其進行服務。可能還需要實現某些身份驗證機制,以限制誰可以訪問金鑰。在這種情況下,所有段都使用相同的金鑰加密。如果暴露特定金鑰,則定期更改加密金鑰以最小化影響可能是有益的,這被稱為金鑰旋轉。針對動態更換金鑰這點,需要後端能力支撐。設想生成金鑰以後需要對切片進行加密,更換一次金鑰需要等待較長時間,不一定能滿足播放實時性要求。
參考文章
https://onetdev.medium.com/custom-key-acquisition-for-encrypted-hls-in-videojs-59e495f78e52
http://hlsbook.net/how-to-encrypt-hls-video-with-ffmpeg/
https://github.com/videojs/videojs-contrib-hls/issues/1337
https://doc.xuwenliang.com/docs/video_audio/3422
https://imweb.io/topic/59819d7bf8b6c96352a593ff
https://github.com/video-dev/hls.js/issues/1437
https://zhuanlan.zhihu.com/p/102125509
相關文章
- 基於.Net 的 AvaloniUI 多媒體播放器方案彙總UI播放器
- 基於 SRS+NG 搭建 HLS 直播流媒體伺服器伺服器
- 基於WiFi的防盜報警Python指令碼WiFiPython指令碼
- 淺析 HLS 流媒體協議協議
- SpringBoot整合FastDFS+Nginx整合基於Token的防盜鏈Spring BootASTNginx
- 基於OkHttp的一種防抓包方案HTTP
- Android多媒體之視訊播放器(基於MediaPlayer)Android播放器
- 簡訊介面防盜刷解決方案
- 多媒體的格式
- 基於 SQL 解析的 JPA 多租戶方案SQL
- JMeter流媒體線上播放HLS外掛BlazeMeter - HLS Plugin實現視訊線上播放壓測JMeterPlugin
- Nginx 防盜鏈Nginx
- 防盜鏈的實現方法
- 自媒體多平臺同步,自媒體多平臺分發,自媒體多平臺管理
- Golang開源流媒體伺服器(RTMP/RTSP/HLS/FLV等協議)Golang伺服器協議
- 為SRS流媒體伺服器新增HLS加密功能(附原始碼)伺服器加密原始碼
- Commvault+XSKY 推出基於 Object Lock 的防勒索病毒聯合方案Object
- 基於區塊鏈技術的全程追溯防偽解決方案區塊鏈
- 產品防盜版
- 基於多種場景DataGuard切換方案
- 流媒體調研:雲端視訊監控與視覺化對講視覺化
- 首款基於EOS生態研發的區塊鏈媒體平臺,陀螺財經APP上線啦!區塊鏈APP
- iOS自動化測試調研方案iOS
- Jar包衝突解決方案調研JAR
- 調研:如何基於Linux平臺實現自主設計的排程器Linux
- 基於 Ionic 2 多主題、多租戶構建方案探索
- 開源服務lalserver支援多種鑑權防盜鏈方式Server
- 微前端中實現沙箱環境的方案調研前端
- node實現防盜鏈
- Cision:2023全球媒體調查
- 用純RUST手擼一個開源流媒體服務(RTMP/HTTPFLV/HLS)XIURustHTTP
- 基於微前端qiankun的多頁籤快取方案實踐前端快取
- 1688 商家基於 HarmonyOS 的多屏協同直播技術方案
- 微信圖片防盜鏈解決方案:自建代理繞過限制。
- iOS Out-Of-Memory 原理闡述及方案調研iOS
- surging 基於流媒體服務如何叢集分流
- 基於SRS搭建RTMP直播流媒體伺服器伺服器
- 解密微信域名防封、防紅系統的具體方案解密