本文只討論應用於瀏覽器環境的流媒體協議的加密。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 國際許可協議進行許可。