?背景介紹
HLS視頻加密是一種基于HTTP Live Streaming(HLS)協議的加密技術。它的核心思想是將視頻切片進行加密處理,在客戶端播放時需要先獲取解密密鑰才能正常偶發。通過這種方式,HLS加密可以有效防止未經授權的第三方竊取視頻內容,從而保障了視頻內容的版權和安全。數據萬象媒體處理服務提供了一套HLS視頻加密方案,方便用戶各個場景的需求。
?HLS加密方案
整體加密方案如下圖所示:
?
痛點
在我們日常的工作生活中,如果沒有HLS加密,會帶來以下問題:
-
視頻內容被非法下載和分享:沒有加密的視頻內容容易被非法下載和分享,導致付費業務受到威脅。
-
影響用戶體驗:為了提高視頻的安全性,可能需要采用更復雜的驗證和授權機制。這可能會增加用戶的操作復雜度,降低用戶體驗。
-
增加服務器的負擔:如果采用客戶端解密的技術,服務器需要處理更多的請求和計算量,可能會對延遲和性能造成一定的不良影響。
?使用場景
-
直播賽事:體育賽事、音樂會等大型活動需要進行直播,HLS加密可以有效防止盜版和非法傳播。
-
在線教育:在線教育平臺需要保護課程內容的版權,HLS加密可以確保課程內容不被非法竊取。
-
付費視頻:電影、電視劇等付費視頻內容需要進行版權保護,HLS加密可以有效防止盜版行為。
-
企業會議:企業的重要會議、內部培訓等內容需要進行保密處理,HLS加密可以確保這些內容不被泄露。
?操作指南
生成加密視頻
一、模版設置
1. 開通媒體處理
進入存儲桶界面,點擊數據處理中的媒體處理,點擊開通。
2. 創建HLS轉碼模版
點擊任務與工作流里的模版配置,點擊創建轉碼模版
2.1 輸入模版名稱,封裝格式選擇HLS。
2.2 打開視頻加密開關
視頻參數和音頻參數根據需要填寫,在高級設置里打開視頻加密開關
二、創建轉碼任務
在當前存儲桶上傳任意視頻文件,點擊任務管理里的創建任務。
1. 生成m3u8加密文件
源文件路徑選擇剛剛上傳的視頻文件,模版類型選擇自定義模版,選擇第二步創建的hls轉碼模版,記住目標路徑和目標文件名,產出文件就是我們需要的加密視頻文件。
2. 確定產物文件
找到創建任務時填的產物路徑,可看到生成后的加密文件
播放加密視頻
控制臺媒體處理,視頻加密配置模塊,展示播放密鑰(playKey,部署后端服務的時候會用到)
拿到生成的m3u8視頻文件和播放秘鑰(playKey)后,就可以開始搭建服務,播放剛剛加密的m3u8視頻文件。
本文前端部分以js代碼為例,服務端以nodejs為例,來說明整個使用過程。
三、前端部分
1. 首先下載hls加密代碼包(https://bjtest-10008930.cos.ap-shanghai.myqcloud.com/hlsCode/hls%E5%8A%A0%E5%AF%86%E4%BB%A3%E7%A0%81%E5%8C%85.zip)
2. 在頁面中引入壓縮包中cos_hls.js、jsencrypt.js 和 hls.js。
3.?根據播放器種類,在頁面中引入壓縮包中文件,目前支持三種類型(hls.js/tcplayer/video.js)。
hls.js:
<script src="./cos_hls.js"></script>
<script src="./hls.js"></script>
<script src="./jsencrypt.js"></script>
tcplayer:
<link href="https://web.sdk.qcloud.com/player/tcplayer/release/v4.2.2/tcplayer.min.css" rel="stylesheet"/>
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.2.2/libs/hls.min.0.13.2m.js"></script>
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.2.2/tcplayer.v4.2.2.min.js"></script>
<script src="./cos_hls.js"></script>
<script src="./jsencrypt.js"></script>
video.js:
<link href="https://vjs.zencdn.net/8.11.8/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/8.11.8/video.js"></script>
<script src="./cos_hls.js"></script>
<script src="./jsencrypt.js"></script>
4. 前端使用cos_hls.js文件中封裝好的cosHls對象來播放m3u8文件,用戶按照如下規則傳入參數,即可實現播放功能。?
<script>// cosHLs為cos_hls.js封裝的對象,使用play方法播放視頻文件cosHls.play({// video標簽的idcontainer: 'video',// 支持的播放器種類(hls.js/tcplayer/video.js)playerType: 'hls.js',// 請求m3u8接口的文件地址src: 'https://examplebucket-1250000000.cos.ap-beijing.myqcloud.com/hls/video.m3u8?ci-process=pm3u8',// 標記src里的域名是不是CDN域名(false/true)// useCdn: false,// 請求token和簽名的函數getToken(opt, callback) {// 加密公鑰,不需要用戶填寫,sdk會自動生成var publicKey = opt.publicKey;// 請求m3u8接口的文件地址,不需要用戶填寫,sdk會自動生成var src = opt.src;// 是否返回加密內容,與cosHls對象的ProtectContentKey參數保持一致,不需要用戶填寫,sdk會自動生成var protectContentKey = opt.ProtectContentKey;// 新建xhr對象,進行請求var xhr = new XMLHttpRequest();xhr.withCredentials = true;// /samples/hls/token為自定義請求地址,用戶可自自定義xhr.open('POST', `/hls/token`, true);xhr.setRequestHeader('Content-Type', 'application/json')// 請求成功返回authorization 和 tokenxhr.onload = function () {var r = JSON.parse(xhr.responseText);var authorization = r.authorizationvar token = r.tokencallback(null, {authorization, token});};xhr.onerror = function () {callback('get token error');};// node服務所需要的參數,已從sdk獲取,不需要用戶填寫var data = {src: src,publicKey: window.btoa(publicKey),protectContentKey: protectContentKey};xhr.send(JSON.stringify(data));}})
</script>
四、服務端部分
服務端,以 Nodejs 為例,主要代碼如下:
const COS = require('cos-nodejs-sdk-v5');
const base64Url = require('base64-url');
const express = require('express');
const crypto = require('crypto');// 配置參數
const config = {// 獲取騰訊云密鑰,建議使用限定權限的子用戶的密鑰 https://console.cloud.tencent.com/cam/capisecretId: process.env.SecretId,secretKey: process.env.SecretKey,// 播放秘鑰,可在媒體處理模塊獲取 https://console.cloud.tencent.com/cos/bucket?bucket=xxxx-100000®ion=ap-xxx&type=ci&anchorType=videoplayKey: process.env.playKey,// 目標存儲桶名稱,可在存儲桶列表頁獲取 https://console.cloud.tencent.com/cos/bucketbucket: 'xxx',// 目標存儲桶地域,可在存儲桶列表頁獲取 https://console.cloud.tencent.com/cos/bucketregion: 'xxx'
};// 創建臨時密鑰服務和用于調試的靜態服務
const app = express();app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));router.post('/hls/token', (req, res, next) => {// 從接口拿到文件地址,加密公鑰,是否返回加密內容const body = req.body;const src = body.src;const publicKey = body.publicKey;const protectContentKey = body.protectContentKey;// 如在某些特殊場景需要用HLS標準加密(例如小程序里播放/iOSWebview),可以去掉下面的限制判斷并做好來源限制只允許小程序來源。// 代碼示例只允許 protectContentKey 傳 1,原因:如果允許傳入 0 播放流程會走 HLS 標準加密會有風險。const userAgent = req.headers['user-agent'] || '';const uaWhiteList = ['Safari', 'wechatdevtools', 'MiniProgramEnv'];const isUaAllow = uaWhiteList.some(item => userAgent.includes(item));// 只有白名單的瀏覽器,才能走標準加密if (!protectContentKey && !isUaAllow) {res.status(400);return res.send({code: -1, message: 'protectContentKey=0 not allowed'});}// src 鏈接校驗if (!src || !srcReg.test(src)) return res.send({code: -1, message: 'src format error'});if (!publicKey) return res.send({code: -1, message: 'publicKey empty'});// 解析 urlconst { bucket, region } = config;const { token, authorization } = getToken({publicKey, protectContentKey, bucket, region, src}, res)res.send({code: 0, message: 'ok', token, authorization});
});const srcReg = /^https?:\/\/([^/]+)\/([^?]+)/;
const ciHostReg = /^[^.]+\.ci\.[^.]+\.myqcloud\.com$/;function getToken({publicKey, protectContentKey, bucket, region, src}) {const m = src.match(srcReg);const srcHost = m[1];const pathKey = m[2];const query = {};const isCiHost = ciHostReg.test(srcHost);src.replace(/^([^?]+)(\?([^#]+))?(#.*)?$/, '$3').split('&').forEach(item => {const index = item.indexOf('=');const key = index > -1 ? item.slice(0, index) : item;let val = index > -1 ? item.slice(index + 1) : '';query[key] = decodeURIComponent(val);});let objectKey = isCiHost ? query.object : pathKey;const header = {"alg": "HS256","typ": "JWT"}const appId = bucket.slice(bucket.lastIndexOf('-') + 1);let payload = {Type: "CosCiToken",AppId: appId,BucketId: bucket,Issuer: "client",IssuedTimeStamp: Math.floor((new Date().getTime() - 30 * 1000) / 1000),ProtectSchema: "rsa1024",PublicKey: publicKey,ProtectContentKey: protectContentKey || 0,UsageLimit: 50,Object: objectKey,};let Header = base64Url.encode(JSON.stringify(header))let PayLoad = base64Url.encode(JSON.stringify(payload))let data = Header + "." + PayLoadlet hash = crypto.createHmac('sha256', config.playKey).update(data).digest();let Signature = base64Url.encode(hash);let token = Header + '.' + PayLoad + '.' + Signaturelet authorization = COS.getAuthorization({SecretId: config.secretId,SecretKey: config.secretKey,Method: 'get',Pathname: `/${objectKey}`,Query: {'ci-process': 'pm3u8'},});return {token, authorization};
}
五、效果體驗
完成前后端的代碼后,啟動服務,即可開始播放加密視頻。
在線體驗地址:?
https://cos.cloud.tencent.com/samples/hls/private-encrypt/
方案接入優勢
-
接入簡單:支持多個開源通用播放器,定制化能力強。
-
支持場景豐富:PC Web、Android WebView,Android/iOS移動端App
-
不兼容的場景自動降級:因為 iOS Webview 不兼容 Media Source Extensions,會自動降級為標準加密方案。減少開發兼容成本。
總結
數據萬象媒體處理新增視頻加密,旨在讓用戶能夠更加方便地使用視頻加密功能,提高用戶體驗。同時,我們也會繼續關注用戶的反饋,不斷優化和改進數據萬象媒體處理的用戶體驗,為用戶提供更好的服務。