HLS视频加密,让您的视频内容更安全!
背景介绍
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加密代码包
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标签的id
container: '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 和 token
xhr.onload = function () {
var r = JSON.parse(xhr.responseText);
var authorization = r.authorization
var token = r.token
callback(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/capi
secretId: process.env.SecretId,
secretKey: process.env.SecretKey,
// 播放秘钥,可在媒体处理模块获取 https://console.cloud.tencent.com/cos/bucket?bucket=xxxx-100000®ion=ap-xxx&type=ci&anchorType=video
playKey: process.env.playKey,
// 目标存储桶名称,可在存储桶列表页获取 https://console.cloud.tencent.com/cos/bucket
bucket: 'xxx',
// 目标存储桶地域,可在存储桶列表页获取 https://console.cloud.tencent.com/cos/bucket
region: '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'});
// 解析 url
const { bucket, region } = config;
const { token, authorization