HLS视频加密,让您的视频内容更安全!

海哥  论坛元老 | 2024-9-15 08:35:51 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1000|帖子 1000|积分 3000

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 背景介绍

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:
  1. <script src="./cos_hls.js"></script>
  2. <script src="./hls.js"></script>
  3. <script src="./jsencrypt.js"></script>
复制代码
tcplayer:
  1. <link href="https://web.sdk.qcloud.com/player/tcplayer/release/v4.2.2/tcplayer.min.css" rel="stylesheet"/>
  2. <script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.2.2/libs/hls.min.0.13.2m.js"></script>
  3. <script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.2.2/tcplayer.v4.2.2.min.js"></script>
  4. <script src="./cos_hls.js"></script>
  5. <script src="./jsencrypt.js"></script>
复制代码
video.js:
  1. <link href="https://vjs.zencdn.net/8.11.8/video-js.css" rel="stylesheet" />
  2. <script src="https://vjs.zencdn.net/8.11.8/video.js"></script>
  3. <script src="./cos_hls.js"></script>
  4. <script src="./jsencrypt.js"></script>
复制代码
4. 前端使用cos_hls.js文件中封装好的cosHls对象来播放m3u8文件,用户按照如下规则传入参数,即可实现播放功能。 
  1. <script>
  2.     // cosHLs为cos_hls.js封装的对象,使用play方法播放视频文件
  3.     cosHls.play({
  4.         // video标签的id
  5.         container: 'video',
  6.         // 支持的播放器种类(hls.js/tcplayer/video.js)
  7.         playerType: 'hls.js',
  8.         // 请求m3u8接口的文件地址
  9.         src: 'https://examplebucket-1250000000.cos.ap-beijing.myqcloud.com/hls/video.m3u8?ci-process=pm3u8',
  10.         // 标记src里的域名是不是CDN域名(false/true)
  11.         // useCdn: false,
  12.         // 请求token和签名的函数
  13.         getToken(opt, callback) {
  14.             // 加密公钥,不需要用户填写,sdk会自动生成
  15.             var publicKey = opt.publicKey;
  16.             // 请求m3u8接口的文件地址,不需要用户填写,sdk会自动生成
  17.             var src = opt.src;
  18.             // 是否返回加密内容,与cosHls对象的ProtectContentKey参数保持一致,不需要用户填写,sdk会自动生成
  19.             var protectContentKey = opt.ProtectContentKey;
  20.             // 新建xhr对象,进行请求
  21.             var xhr = new XMLHttpRequest();
  22.             xhr.withCredentials = true;
  23.             // /samples/hls/token为自定义请求地址,用户可自自定义
  24.             xhr.open('POST', `/hls/token`, true);
  25.             xhr.setRequestHeader('Content-Type', 'application/json')
  26.             // 请求成功返回authorization 和 token
  27.             xhr.onload = function () {
  28.                 var r = JSON.parse(xhr.responseText);
  29.                 var authorization = r.authorization
  30.                 var token = r.token
  31.                 callback(null, {authorization, token});
  32.             };
  33.             xhr.onerror = function () {
  34.                 callback('get token error');
  35.             };
  36.             // node服务所需要的参数,已从sdk获取,不需要用户填写
  37.             var data = {
  38.                 src: src,
  39.                 publicKey: window.btoa(publicKey),
  40.                 protectContentKey: protectContentKey
  41.             };
  42.             xhr.send(JSON.stringify(data));
  43.         }
  44.     })
  45. </script>
复制代码
四、服务端部分

服务端,以 Nodejs 为例,主要代码如下:
  1. const COS = require('cos-nodejs-sdk-v5');
  2. const base64Url = require('base64-url');
  3. const express = require('express');
  4. const crypto = require('crypto');
  5. // 配置参数
  6. const config = {
  7.     // 获取腾讯云密钥,建议使用限定权限的子用户的密钥 https://console.cloud.tencent.com/cam/capi
  8.     secretId: process.env.SecretId,
  9.     secretKey: process.env.SecretKey,
  10.     // 播放秘钥,可在媒体处理模块获取 https://console.cloud.tencent.com/cos/bucket?bucket=xxxx-100000&region=ap-xxx&type=ci&anchorType=video
  11.     playKey: process.env.playKey,
  12.     // 目标存储桶名称,可在存储桶列表页获取 https://console.cloud.tencent.com/cos/bucket
  13.     bucket: 'xxx',
  14.     // 目标存储桶地域,可在存储桶列表页获取 https://console.cloud.tencent.com/cos/bucket
  15.     region: 'xxx'
  16. };
  17. // 创建临时密钥服务和用于调试的静态服务
  18. const app = express();
  19. app.use(bodyParser.json());
  20. app.use(bodyParser.urlencoded({ extended: true }));
  21. router.post('/hls/token', (req, res, next) => {
  22.     // 从接口拿到文件地址,加密公钥,是否返回加密内容
  23.     const body = req.body;
  24.     const src = body.src;
  25.     const publicKey = body.publicKey;
  26.     const protectContentKey = body.protectContentKey;
  27.    
  28.     // 如在某些特殊场景需要用HLS标准加密(例如小程序里播放/iOSWebview),可以去掉下面的限制判断并做好来源限制只允许小程序来源。
  29.     // 代码示例只允许 protectContentKey 传 1,原因:如果允许传入 0 播放流程会走 HLS 标准加密会有风险。
  30.     const userAgent = req.headers['user-agent'] || '';
  31.     const uaWhiteList = ['Safari', 'wechatdevtools', 'MiniProgramEnv'];
  32.     const isUaAllow = uaWhiteList.some(item => userAgent.includes(item));
  33.     // 只有白名单的浏览器,才能走标准加密
  34.     if (!protectContentKey && !isUaAllow) {
  35.         res.status(400);
  36.         return res.send({code: -1, message: 'protectContentKey=0 not allowed'});
  37.     }
  38.     // src 链接校验
  39.     if (!src || !srcReg.test(src)) return res.send({code: -1, message: 'src format error'});
  40.     if (!publicKey) return res.send({code: -1, message: 'publicKey empty'});
  41.     // 解析 url
  42.     const { bucket, region } = config;
  43.     const { token, authorization } = getToken({publicKey, protectContentKey, bucket, region, src}, res)
  44.     res.send({code: 0, message: 'ok', token, authorization});
  45. });
  46. const srcReg = /^https?:\/\/([^/]+)\/([^?]+)/;
  47. const ciHostReg = /^[^.]+\.ci\.[^.]+\.myqcloud\.com$/;
  48. function getToken({publicKey, protectContentKey, bucket, region, src}) {
  49.     const m = src.match(srcReg);
  50.     const srcHost = m[1];
  51.     const pathKey = m[2];
  52.     const query = {};
  53.     const isCiHost = ciHostReg.test(srcHost);
  54.     src.replace(/^([^?]+)(\?([^#]+))?(#.*)?$/, '$3').split('&').forEach(item => {
  55.         const index = item.indexOf('=');
  56.         const key = index > -1 ? item.slice(0, index) : item;
  57.         let val = index > -1 ? item.slice(index + 1) : '';
  58.         query[key] = decodeURIComponent(val);
  59.     });
  60.     let objectKey = isCiHost ? query.object : pathKey;
  61.     const header = {
  62.         "alg": "HS256",
  63.         "typ": "JWT"
  64.     }
  65.     const appId = bucket.slice(bucket.lastIndexOf('-') + 1);
  66.     let payload = {
  67.         Type: "CosCiToken",
  68.         AppId: appId,
  69.         BucketId: bucket,
  70.         Issuer: "client",
  71.         IssuedTimeStamp: Math.floor((new Date().getTime() - 30 * 1000) / 1000),
  72.         ProtectSchema: "rsa1024",
  73.         PublicKey: publicKey,
  74.         ProtectContentKey: protectContentKey || 0,
  75.         UsageLimit: 50,
  76.         Object: objectKey,
  77.     };
  78.     let Header = base64Url.encode(JSON.stringify(header))
  79.     let PayLoad = base64Url.encode(JSON.stringify(payload))
  80.     let data = Header + "." + PayLoad
  81.     let hash = crypto.createHmac('sha256', config.playKey).update(data).digest();
  82.     let Signature = base64Url.encode(hash);
  83.     let token = Header + '.' + PayLoad + '.' + Signature
  84.     let authorization = COS.getAuthorization({
  85.         SecretId: config.secretId,
  86.         SecretKey: config.secretKey,
  87.         Method: 'get',
  88.         Pathname: `/${objectKey}`,
  89.         Query: {'ci-process': 'pm3u8'},
  90.     });
  91.     return {token, authorization};
  92. }
复制代码



五、结果体验

完成前后端的代码后,启动服务,即可开始播放加密视频。


在线体验地址: 
https://cos.cloud.tencent.com/samples/hls/private-encrypt/

方案接入上风




  • 接入简单:支持多个开源通用播放器,定制化能力强。
  • 支持场景丰富:PC Web、Android WebView,Android/iOS移动端App
  • 不兼容的场景自动降级:因为 iOS Webview 不兼容 Media Source Extensions,会自动降级为标准加密方案。减少开发兼容成本。

总结


数据万象媒体处理新增视频加密,旨在让用户可以或许更加方便地使用视频加密功能,进步用户体验。同时,我们也会继承关注用户的反馈,不绝优化和改进数据万象媒体处理的用户体验,为用户提供更好的服务。



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表