本文只讨论应用于浏览器环境的流媒体协议的加密。javascript
付费观看视频的模式是不少平台的核心业务,若是视频被录制并不是法传播,付费业务将受到严重威胁。所以对视频服务进行加密的技术变得尤其重要。css
本文所指的视频加密是为了让要保护的视频不能轻易被下载,即便下载到了也是加密后的内容,其它人解开加密后的内容须要付出很是大的代价。html
没法作到严格的让要保护的视频不被录制,缘由在于你须要在客户端播放出视频的原内容,解密的流程在客户端的话不法分子就能模拟整个流程,最保守也能用屏幕录制软件录制到视频的原内容(能够经过加水印的方法缓解下)。咱们的目标是让他获取原内容的代价更大。前端
本文为你们提供了一套简单的基于HLS流媒体协议,使用video.js + NodeJS + FFmpeg等相关技术实现的m3u8+ts+aes128视频加密及播放的解决方案示例。java
起初是为了将工做中已有的基于Flash的视频播放器替换为不依赖Flash的HTML5视频播放器,主要使用了现有的video.js开源播放器作的定制化开发。当完成视频播放器的制做后,在进一步延伸Web端视频加密的相关内容时,开始了解并逐渐深刻的研究了相关视频加密内容。最终经过整理概括,以及自身的理解,作了这个简单的Demo。目的是为了可以给在视频加密这方面有相同目的的道友提供微薄的帮助,要是能起到抛砖引玉的效果,天然是再好不过了。node
1.安装项目环境git
2.启动项目github
npm start
,启动项目http://localhost:3000
3.权限登陆web
本项目的核心原理其实就是讲解了一个视频源从正常的mp4格式如何变为加密后的m3u8文件+ts文件+key秘钥文件,以后又如何在服务端被限制访问,最终可以在客户端正常播放的视频加密、解密并播放的流程。express
项目原理图示
项目目录说明
video-hls-encrypt/ .............................. hls视频加密项目根目录
├── app/ .............................. express框架默认的app根目录
│ ├── bin/ .............................. express框架启动的bin目录
│ │ └── www .............................. express框架启动的www文件
│ ├── controllers/ .............................. 项目控制器目录,服务器相关的逻辑代码
│ │ ├── encrypt.js .............................. 加密逻辑代码
│ │ └── upload.js .............................. 上传逻辑代码
│ ├── node_modules/ .............................. express框架须要的相关npm依赖包,即package.json文件相对应的依赖包
│ │ └── ...
│ ├── public/ .............................. express框架静态文件目录,客户端请求的相关静态文件
│ │ ├── javascripts .............................. 客户端的js文件目录
│ │ │ ├── encrypt.js .............................. 加密功能相关逻辑代码
│ │ │ ├── index.js .............................. 主页相关逻辑代码
│ │ │ ├── player.js .............................. 播放器相关逻辑代码
│ │ │ ├── socket.io.js .............................. socket.io.js 类库源文件
│ │ │ └── utils.js .............................. 工具类
│ │ ├── key/ .............................. 秘钥相关目录
│ │ │ ├── encrypt.key .............................. 秘钥文件
│ │ │ └── key_info.key .............................. ffmpeg加密视频转换相关文件
│ │ ├── libs/ .............................. 第三方类库目录
│ │ │ ├── videojs/ .............................. videojs 相关代码
│ │ │ └── videojs-contrib-hls/ .............................. videojs-contrib-hls 相关代码
│ │ ├── stylesheets/ .............................. css样式目录
│ │ │ └── common.css .............................. 通用样式表
│ │ └── videos/ .............................. 视频资源目录
│ │ ├── encrypt/ .............................. 加密后的视频资源目录
│ │ └── noencrypt/ .............................. 加密前的视频资源目录
│ ├── routes/ .............................. express框架路由目录
│ │ └── router.js .............................. express路由
│ ├── views/ .............................. express框架ejs模板目录
│ │ ├── encrypt.ejs .............................. 视频加密页面
│ │ ├── error.ejs .............................. 错误页面
│ │ ├── index.ejs .............................. 主页
│ │ ├── login.ejs .............................. 登陆页面
│ │ ├── player.ejs .............................. 播放器页面
│ │ └── upload.ejs .............................. 上传视频页面
│ ├── app.js .............................. express程序入口
│ ├── nodemon.json .............................. node服务器热更新插件nodemon对应的配置文件
│ └── package.json .............................. express框架须要的第三方依赖包配置文件
├── .gitignore
├── README.md .............................. 项目说明文档
└── TODO-List.md .............................. 项目开发计划文档
复制代码
源码简析
//静态资源访问限制
app.use(function (req, res, next) {
var suffix = /(\.key)$/g;//后缀格式指定
if ( suffix.test(req.path)) {
console.log(req.session.username,'++++请求key文件了');
if((req.session.username != 'admin')){
return res.send('请求非法');
}else{
console.log('+++++请求key文件了,而且已经登陆,登陆名为:',req.session.username);
next();
}
}
else {
next();
}
});
复制代码
/**
* 加密处理方法
* @param options 加密数据的相关参数
* @param socket socket输出
* @param callback 回调函数
*/
function encryptFun(options,socket, callback) {
var _name = options.fileName.split('.')[0];
var _type = options.fileName.split('.')[1];
var _encryptPath = options.encryptPath + '/' + _name;
var _videoPath = options.noencryptPath + '/' + options.fileName;
var _keyInfoPath = './public/key/key_info.key';
var _outputPath = _encryptPath + '/playlist.m3u8';
console.log('begin encrypt Fun');
if (_type == 'mp4') {
ffmpegCommand(_videoPath)
.addOption('-hls_time', '10') //设置每一个片断的长度
.addOption('-hls_key_info_file', _keyInfoPath)
.save(_outputPath)
.on('end', function () {
socket.emit('encrypt-event',{msg:'Encrypt the ' + options.fileName + ' file OK!',type:1});
callback(null, 'Encrypt the ' + options.fileName + ' file OK!');
})
.on('stderr', function (stderrLine) {
console.log('Stderr output: ' + stderrLine);
socket.emit('encrypt-event',{msg:stderrLine});
})
.on('error', function (err, stdout, stderr) {
console.log('Cannot process video: ' + err.message);
socket.emit('encrypt-event',{msg:err.message});
callback(err, err.message);
});
}
else{
callback('type err','file type is not mp4.');
}
}
复制代码
<script src="javascripts/utils.js"></script>
<script src="libs/videojs/video.min.js"></script>
<script src="libs/videojs-contrib-hls/videojs-contrib-hls.js"></script>
<script src="javascripts/player.js"></script>
复制代码
如下的内容均为我的观点,仅供参考
因为本人自身是作前端开发的,因此不少相关的示例都是基于前端考虑,对于后端的相应的策略并非很专业。好比后端服务器,也采用的是偏前端的NodeJS
。我想表达的是,在整套解决方案中,我主要作了3件事:
FFmpeg
转换为加密后的m3u8
文件和ts
文件以及关键的加密密钥key
文件;video.js
及相关的videojs-contrib-hls.js
实现客户端的视频文件解密,并播放。 所以能够看出关于视频加密的解决方案中,最重要的实际上是如何保护加密密钥key
文件,而这部分工做更多的是在于服务器端的相关策略,好比可使用cookie
、session
相关技术、添加自定义token
校验、有效时长机制等等方法保证秘钥key文件的相对安全性、可靠性。
而如何将视频源文件转化为对应的加密后的文件,能够更多的研究开源库FFmpeg
的使用,甚至若是没有迫切需求,能够考虑使用第三方视频云服务商的相关解决方案。至于客户端的视频解密,也能够研究video.js
相关的内容。
本做品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。