知識付費——移動端音視頻加密、防盜播實現方案


近幾年移動端知識付費App,越來越多越來越火爆。例如:網易公開課、網易雲課堂、樊登讀書、邏輯思維、i春秋,甚至於知乎App都上架付費課程了。
移動端付費課程,基本是以視頻+音頻形式呈現給大家的。那么對於這些付費課程:如何在保證用戶體驗的前提下,防止媒體資源被盜播,維護內容生產者的利益,就成為一個急需解決的問題

注意:保證用戶體驗是前提。否則再好的課,用戶體驗垃圾,也賣不出去。

如今市面上,移動端加密、防盜播的方式很多。這里只是討論一種:我認為的用戶體驗較好,技術實現成熟,又有效防盜播的方式

注意:防止盜播,並不能100%杜絕盜播。只能不斷增加App的破解成本,完全無法破解的App是不存在的。所以,想100%防止盜播也是不可能實現的。

一、實現方案

這里采用的方案是:客戶端播放AES-128加密的m3u8媒體資源

為什么是m3u8 ?

  • m3u8采用AES-128對稱加密算法加密,技術成熟穩定
  • 前邊說了,保證用戶體驗為前提
    音視頻播放過程中,用戶進入播放頁后,音視頻的秒開率(1秒內成功加載的播放數/播放總數)是影響用戶體驗的重要指標;m3u8媒體資源是一個文本文件,其由一個個ts視頻片段的播放地址構成,選擇合適的ts切片大小,能有效提高音視頻的秒開率,保證用戶的觀看體驗。

用戶體驗的大前提滿足了,那如何實現呢?

  • 客戶端播放的視頻源為 AES-128對稱加密的 m3u8 媒體資源;
    播放地址最終組織形式如下:
https://domain/course101.m3u8?playKey=i_am_decrypting_key101

  • 播放地址 https://domain/course101.m3u8 與playKey 需從服務端獲取;
    加密m3u8的解密關鍵就在於playKey,因此,防止playKey被破解是防盜播的一個關鍵點
  • 將最終播放地址交於播放器播放

二、實現舉例

對於m3u8媒體資源,無論是 視頻切片加密ts視頻片段解密播放 在技術實現上已經非常成熟,不存在技術壁壘,實現已經不是問題。
那么擺在移動端最主要的問題就是:防止媒體資源被盜播,維護內容生產者的利益

注:雖然技術實現已經不是問題,但這里還是會把 移動端技術實現的細節和 防破解(防盜播)的實現細節進行呈現。

技術實現上,大概分為以下幾個步驟:

  • 獲取媒體資源播放地址
  • 獲取媒體資源的解密token (playKey)
  • 拼接最終播放地址,播放m3u8媒體資源

下面我們從移動端請求課程內容列表,到成功播放的全過程來舉一個例子:

1、獲取ID為101課程的內容列表

首先通過課程ID 101向服務端發起請求,獲取該課程的內容列表。請求方式和返回結果如下:

a、發起請求:

https://domain/xxx/getCourseList.do?courseId=101

為了簡單易懂,這里簡單模擬一個get請求:

  • 請求參數 courseId 為 101
  • 請求地址為 https://domain/xxx/getCourseList.do
  • 獲取id為101的課程,其對應的內容列表。

b、返回結果:

課程101的課程內容列表如下:

[
    {
      "mediaId": "101", //媒體資源id
      "mediaUrl": "n3GuNo5Rc44anmLGrRU8Rne/JU9cHzc1vXZWiYEwcD0=", // 媒體資源的m3u8播放地址
      "encryptId": "LLVahEH+HjZEOJk6RfJtww==" // 獲取媒體資源playKey的encryptId
    },
    {
      "mediaId": "102",
      "mediaUrl": "n3GuNo5Rc44anmLGrRU8RlKQGcM3X5R3oVqpuCrTpDk=",
      "encryptId": "Ez3wHHWx5ddq+D2miV2dFg=="
    },
    {
      "mediaId": "103",
      "mediaUrl": "n3GuNo5Rc44anmLGrRU8RqLaIqPDWyZQ5VotuUSyNI8=",
      "encryptId": "R5a31ZJIy9Z5+tNPplxHLQ=="
    }
  ]

正如注釋中寫的:

  • mediaId 是媒體資源id ;
  • mediaUrl媒體資源的m3u8播放地址
    可能會疑問: n3GuNo5Rc44anmLGrRU8Rne/JU9cHzc1vXZWiYEwcD0= 是什么鬼,為什么不像播放地址?
    這里正是防止媒體資源被盜播,維護內容生產者的利益的 第二步
    這里將資源地址https://domain/course101.m3u8進行了一個簡單的AES加密
    對於其資源地址的加解密,會在下文進行詳細說明。
  • encryptId 則是 用於獲取媒體資源的解密playKey
    encryptId的具體作用,會在下文中詳細說明

注:這里服務器要做一個用戶權限的校驗:未購買用戶不返回其 mediaUrl 和 encryptId

c、未購買用戶的返回結果:

未購買用戶不返回其 mediaUrl 和 encryptId
正是預防移動端被不良用心的人員,惡意采用Http抓包進行破解。是防止媒體資源被盜播,維護內容生產者的利益的 第一步,也是很重要的一步。 因為:

  • 移動端無論如何防破解,總不能100%保證無法破解;
  • 想要獲取播放地址,必須購買課程,對於用心不了的人員,增加了其破解成本;

未購買用戶,通過課程ID 101向服務端發起請求,返回數據如下:

[
    {
      "mediaId": "101",
      "mediaUrl": "",
      "encryptId": ""
    },
    {
      "mediaId": "102",
      "mediaUrl": "",
      "encryptId": ""
    },
    {
      "mediaId": "103",
      "mediaUrl": "",
      "encryptId": ""
    }
  ]

注:未購買用戶,請求某課程列表接口時,不要返回 媒體資源的m3u8播放地址 和 獲取媒體資源playKey的encryptId。這很重要

d、mediaUrl與encryptId解密:

為防止移動端App被Http抓包,mediaUrl 與 encryptId 都不是明文傳輸的。因此移動端拿到課程的內容列表后,首先需要對mediaUrl 與 encryptId進行解密。

關於解密:

  • 對稱加密算法,大家可以根據實際需求,自行進行選擇;
  • 解密相關代碼,建議由C語言實現,打成SO添加到移動客戶端中
    原因是增加移動端破解難道,提高破解成本

這里只是采用了簡單的AES對稱加密:

image

在這里插入圖片描述

完成解密后的數據格式如下:

[
    {
      "mediaId": "101", //媒體資源id
      "mediaUrl": "https://domain/course101.m3u8", // 媒體資源的m3u8播放地址
      "encryptId": "qazwsx101" // 獲取媒體資源playKey的encryptId
    },
    {
      "mediaId": "102",
      "mediaUrl": "https://domain/course102.m3u8",
      "encryptId": "qazwsx102"
    },
    {
      "mediaId": "103",
      "mediaUrl": "https://domain/course103.m3u8",
      "encryptId": "qazwsx103"
    }
  ]

2、獲取 playKey

在第1步中,已成功獲取到媒體資源的播放地址 https://domain/course101.m3u8encryptId。為了播放媒體資源,下面來獲取到加密m3u8視頻的解密playKey

這里 playKey 仍然需要從服務端進行獲取,獲取方式如下:

模擬請求

發起請求:

https://domain/xxx/getMediaToken.do?encryptId=C0AFC0A81&mediaId=101

返回結果:

{
  "playKey": "I_am_playkey_001"
}

這里仍然模擬一個簡單get請求:

  • 請求參數 encryptId 為 qazwsx101
  • 請求參數 mediaId 為 101
  • 請求地址為 https://domain/xxx/getMediaToken.do

注:playKey是加密m3u8解密的關鍵,是防止媒體資源被破解的重中之重。

關於 playKey 加密

這里是防止媒體資源被盜播,維護內容生產者的利益的 第三步和第四步

  • 1、playKey 服務端需加密傳輸
  • 2、請求getMediaToken.do接口時,服務端需對該用戶的購買狀態進行驗證,未購用戶不返回其對應的playKey;
  • 3、移動端獲取到playKey后,在SO(C層代碼達成的)中對playKey進行解密;
  • 4、解密后的playKey存在一定的過期時間;或者使用次數限制(建議服務端限定只能使用一次)
    加密算法要與mediaUrl 和encryptId 的解密算法區分開,增加破解成本

3、拼接播放地址

經過以上步驟,購買用戶成功獲取到 播放地址 https://domain/xxx/getMediaToken.do解密key I_am_playkey_001
將mediaUrl 與playKey 拼接起來,可以交給播放器播放了:

https://domain/course101.m3u8?playKey=i_am_decrypting_key101

到此,移動端的工作完成。
OK. 移動端完事大吉

到這里播放器服務端的交互剛剛開始。

這里有必要先介紹一下,加密m3u8視頻的文件格式:

加密m3u8視頻的文件格式

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:19
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="http://domain//hls.key"
#EXT-CUSTOM-YUNXIN:ntsversion=0,ntsprivatedata=d68edb4f4ee3c64233b1ece785758291727d053d
#EXTINF:11.960000,
http://domain/encrypt0.ts
#EXTINF:9.200000,
http://domain/encrypt1.ts
#EXTINF:10.000000,
http://domain/encrypt2.ts
#EXT-X-ENDLIST

以上為加密m3u8視頻的文件格式:

  • 播放器在播放前,會用該地址 http://domain//hls.key向業務服務器發起請求,請求加密m3u8視頻的解密秘鑰

解密秘鑰如下圖所示:

加密m3u8視頻的解密秘鑰並非playKey=i_am_decrypting_key101,而是一個16字節的文件。

image

在這里插入圖片描述

m3u8的解密秘鑰實際是一個16字節的文件。
這里肯定會有很多疑問,別着急,我們繼續前邊的話題播放器服務端交互。

播放器 與 服務端 交互

  • 當 播放器 向 服務端 發起https://domain/course101.m3u8?playKey=i_am_decrypting_key101 請求后;
  • 服務端 處理相對復雜
    a、首先校驗playKey=i_am_decrypting_key101是否有效;
    b、若有效則將加密m3u8視頻中的http://domain//hls.key更換為http://domain//hls.key?playKey=i_am_decrypting_key101
    c、下發m3u8文件給播放器;
  • 播放器收到服務端下發的加密m3u8文件后:
    a、播放器讀取加密m3u8文件,獲取解密秘鑰的請求地址http://domain//hls.key?playKey=i_am_decrypting_key101
    b、播放器服務端發起 http://domain//hls.key?playKey=i_am_decrypting_key101請求,請求解密秘鑰;
  • 服務端收到播放器的請求后,需對playKey=i_am_decrypting_key101進行校驗,查看是否過期或者被使用過,若存在異常則不下發秘鑰;若正常,則下發秘鑰
  • 播放器收到秘鑰文件后,正常播放;

OK. 這次是真的 完事大吉

4、移動端加固

如果僅僅做到上一步就結束了,移動端被破解的概率還是很高。因為SO任然可以被反編譯破解,而且SO的反編譯技術也已經相當成熟。
所以,無論在SO中采用了怎樣復雜的加密算法,SO被反編譯后,還是有被破解的可能

因此,以上步驟都完成后,我們仍然要對我們最終生成的APP進行一次加密。Android端推薦采用APP加固處理

5、SO動態下發,定期更新加密算法

以上步驟都做完,如果APP仍然被破解了。我們可以再加一層防破解處理:動態下發SO,定期更新加密算法
這樣就算線上APP被破解了,也可以在不發版的情況下從容應對,更新一下加密算法就可以了。

三、總結一下

這里來簡單總結一下,上邊介紹的實現步驟 :

image

在這里插入圖片描述

  • a、移動端拿 courseId 向服務端發起Http請求,獲取課程的內容列表
  • b、服務端對用戶進行權限驗證,未購買用戶不返回其對應的播放地址
  • c、移動端在SO層中對 mediaUrl與 encryptId 進行解密
  • d、移動端 用解密后的encryptId,向服務端請求對應媒體資源的 playKey
  • e、服務端對用戶進行權限驗證,未購買用戶不返回其對應的 playKey
  • f、移動端 在SO層中對 playKey 進行解密
    注意,一定要與第三步的解密算法區分開
  • g、拼接mediaUrl 與 playKey ,交給播放器播放;
    到此,移動端工作完成
  • h、播放器服務端發起下發m3u8請求
  • i、服務端校驗playKey;並動態替換m3u8中的URI字段
  • j、播放器從m3u8文件中取出URI字段后,向服務端請求解密秘鑰;
  • k、服務端校驗playKey;並返回解密秘鑰文件;
  • l、播放器播放
    到此,加密m3u8 終於播放出來了
  • m、移動端App加固處理;
  • n、為增強破解難度,這里解密SO可由動態下發,定期更新加密算法
  • m、如果仍然擔心App被破解,服務端下發的解密秘鑰文件可以設置為非明文狀態;客戶端拿到解密秘鑰后,以本地代理的方式設置給播放器進行播放。

注:這里有三個關鍵步驟:1、服務端對用戶進行權限驗證,未購買用戶不返回其對應的播放地址;2、移動端 在SO層中對 playKey 進行解密;3、移動端App加固處理。

這三個關鍵步驟缺一不可,缺少任何一個移動端的破解難度和成本都將大大降低。

  • 未購買用戶不返回其對應的播放地址
    可以極大的降低付費課程被大面積破解的情況出現。因為購買課程亦需要成本。破解的課程越多,那需要購買的課程就越多,破解成本也就越高。
  • 在SO層中對 playKey 進行解密
    對於加密m3u8媒體資源,破解的關鍵就在於playKey,因此playKey的加密算法應足夠的復雜
  • 移動端App加固處理
    移動端App加固,是移動端代碼反編譯非常重要的一環。如果沒有這一環在SO層中對 playKey 進行解密的作用不是很大,因為無論SO中加密算法如何復雜,只要SO被翻遍后,再復雜的加密算法也沒有意義了。

以上為全部處理流程

如果以上步驟都做了,付費音視頻被盜播的可能性應該不大;但仍然存在Http抓包的可能性:

  • http抓包時,會抓到https://domain/course101.m3u8?playKey=i_am_decrypting_key101請求
    由於playKey只有一次使用有效,或者幾個小時的超時時間。因此該內容無法被大規模傳播;
  • http抓包時,會抓到播放器的秘鑰下發請求 http://domain//hls.key?playKey=i_am_decrypting_key101
    由於服務端存在playKey有效性的校驗,下次使用失效,因此也無法大規模傳播;
    如果對服務端明文秘鑰文件下發存在疑慮,可以做以上流程圖的“防盜播9”;
  • 防盜播9 加上APP加固,在實現上應該是比較安全了

如果這樣仍被破解,那我也只能表示佩服 佩服

========== THE END ==========


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM