流媒體基礎實踐之——打流直播碼安全保護(安全防盜鏈)


功能介紹

     所謂安全防盜鏈,是一種加了防盜鏈簽名的URL,經過簽名的URL能夠跟阿麥打流服務器的安全機制進行配合,可以將URL的使用權限定在您的APP上,惡意第三方拿到URL也不能使用和傳播。

(1)推流 - 推流URL加防盜鏈的必要性極高,尤其是在直播碼跟用戶ID(或者DB ID)綁定的情況下,因為客戶的直播碼ID很容易被攻擊者竊取,進而偽裝客戶自己進行搶占式推流,所以為推流URL增加防盜鏈簽名,確保只有真正的客戶主人自己才能在登錄后拿到防盜鏈簽名非常有必要。

(2)播放 - 播放URL加防盜鏈並不是100%必要的,只有在您的視頻源是熱門資源時(比如某個獨家的賽事直播)才比較有價值,因為您要防止您的競爭對手拿到播放地址后在自家的APP里上架這個節目。播放地址防盜鏈引入后的副作用就是播放時可能需要申請防盜鏈簽名,導致直播打開速度不穩定。

原理介紹

下圖都是典型的安全防盜URL,您會發現這些地址都有一個共同的特點,就是在原來的推流或者播放地址后拼接txSecret和txTime參數。

AMAI打流全地址:rtmp://120.26.206.180/live/test?username=123456&password=123456
OBS打流:rtmp://120.26.206.180/live
KEY字符串:test?username=123456&password=123456 test?username=tinywan&password=123456&sign=8935737e61b6fdd586cdab3b15d79633 剔流地址:http://120.26.206.180/rtmp/controllortnoc/drop/client?app=live&name=tinywan

安全防護鏈的構建:

rtmp://120.26.206.180/live/100022_test111?tokenSecret=c7707f5550076bd1c731db0c94ed9366&tokenTime=579ACB15

txTime聲明了該播放器的有效時間,比如5分鍾,當這個地址在5分鍾后被再次使用時,阿麥打流服務器將會判定其為過期地址而拒絕服務。

     但我們知道,簡單聲明txTime是沒有意義的,因為任何攻擊者都可以在一個竊取的URL后面拼接上一個聲明100天過期的txTime,所以騰訊雲需要有一種安全措施確保攻擊者無法偽造txTime,這個安全措施就是txSecret。

txSecret是您的服務器計算出來的一個安全簽名,計算公式是:txSecret = MD5( KEY + stream_id + txTime )

  • KEY
    需要您跟阿麥打流服務器在控制台上提交或者兌換的安全密鑰,您應當確保除了您和阿麥打流服務器之外,外部無法獲知,而且最好定期更換。

  • stream_id
    即直播碼,當同時在線的主播比較多的時候,txTime 很容易碰撞,所以加入 stream_id 來防碰撞。

  • MD5
    最著名的單向不可逆HASH算法了,因為不可逆性,所以攻擊者無法根據txSecret逆向計算出KEY,也就無法根據自己偽造的txTime計算出一個可以通過騰訊雲驗證的txSecret來。

合成方法

安全防盜鏈機制需要您的服務器和阿麥打流服務器協同才能完成,如下圖:

【1】step1 - 交換秘鑰
     首先,您需要在官網的控制台,協商一個加密密鑰,這個加密密鑰用於在您的服務器上生成防盜鏈簽名,由於阿麥打流服務器跟您持有同樣的密鑰,所以您生成的防盜鏈簽名,阿麥打流服務器是可以進行解密確認的。

加密秘鑰分為推流防盜鏈KEY和播放防盜鏈KEY,前者用於生成推流防盜鏈URL,后者用於生成播放防盜鏈URL。目前在上可以自助配置推流防盜鏈KEY,如下圖:

 

播放防盜鏈KEY由於同步周期長,不適合調試期頻繁修改,如您需要配置請聯系我們。

【2】step2 - 生成txTime
      簽名中明文部分為txTime,含義是該鏈接的有效期,比如現在我當前的時間是2016-07-29 11:13:45,而且期望新生成的URL是在5分鍾后即作廢,那么txTime就可以設置為 2016-07-29 11:18:45。

      不過這么長一串時間字符串放在URL里顯然不太“經濟”,實際適用中,我們是把 2016-07-29 11:18:45 轉換成Unix時間戳,也就是1469762325 (轉換方式各種后台編程語言都由直接可用的時間函數來處理),然后轉換成16進制,也就是 txTime=579ACB15。

   /**
     * tokenTime
     * $currentTime :開始時間
     */
    public function getTokenTime($currentTime , $expireTime)
    {
        $tokenTime = dechex(strtotime($currentTime)+$expireTime);
        return strtoupper($tokenTime);
    }

【3】 step3 - 生成txSecret
       txSecret的生成方法是 = MD5(KEY+ stream_id + txTime),這里的 KEY 就是您在Step1中跟騰訊雲交換的加密密鑰,stream_id在本例中為 8888_test001,txTime為剛才計算的579ACB15,MD5即標准的MD5單向不可逆哈希算法。

    /**
     * tokenSecret
     * 順序:MD5(KEY+ streamId + txTime)
     * @param int $streamId
     * @param string $currentTime
     * @param string $expireTime
     * @return string
     */
    public function getTokenSecret($tokenTime,$streamId,$tokenTime)
    {
        $KEY = '8935737e61b6fdd586cdab3b1';
        $tokenSecret = md5($KEY . $streamId . $tokenTime);
        return $tokenSecret;
    }

 【4】step4 - 合成防盜鏈地址
現在我們有了推流(或者播放)URL,有了用來告知騰訊雲該URL過期時間的txTime,有了只有騰訊雲才能解密並且驗證的txSecret,就可以拼合成一個防盜鏈的安全URL了。

 

public function indexAction()
    {
        $this->tag->setTitle('詳情');
        $request = $this->request;
        $domain = Domain::findFirst(array("id = :id:", "bind" => array("id" => 3)));
        if ($domain == false) {
            return $this->showError("未找到推流對象", array(
                "返回域名管理" => "/domainaliyun",
                "返回首頁" => "/"
            ));
        }
        $this->view->setVar("domain", $domain);
        if ($request->isPost()) {
            $original_url = $request->getPost('original_url');
            $deviceId = '1028';
            $currentTime = $request->getPost('startTime');
            $userId = $request->getPost('user_id');
            $expireTime = $request->getPost('expire');

            $streamId = $deviceId.$userId;
            $tokenTime = $this->getTokenTime($currentTime,$expireTime*60);
            $tokenSecret = $this->getTokenSecret($tokenTime,$streamId,$tokenTime);
       // 拼接url
$tokenUrl = $deviceId.'_test'.$userId."?tokenSecret=$tokenSecret&tokenTime=$tokenTime&userId=$userId"; $redis = RedisInstance::getInstance(); $redis->hMset('SIGNTOKEN:'.$userId, [ 'user_id' => $userId, 'sign' => $tokenSecret, 'expire' => $expireTime*60, 'original_url' => $original_url, 'status' => 'enable' ]); //這里保存過期時間,為了給客戶短信通知,這個可以根據User_id去存儲哦 $redis->setex($userId,$expireTime*60,$tokenTime); $this->view->setVar("token_url", $tokenUrl); $this->view->setVar("tokenSecret", $tokenSecret); return TRUE; } }

注意:Redis的鍵過期的時間設置應該是在用戶已近開始打流的時候,也就是你用戶的權限全部驗證通過時候,設置改用戶的userId為一個主鍵的過期時間,該時間也就是鍵過期的鍵值哦;注意在這里添加一句代碼即可

/**
         * 驗證簽名是否合適
         */
        $sign = $redis->hGet('SIGNTOKEN:' . $userId, 'sign');
        $expire = $redis->hGet('SIGNTOKEN:' . $userId, 'expire');
        if ($tokenSecret != $sign) {
            echo "the sign errors";
            header('HTTP/1.0 404 Not Found');
            exit(1);
        } else {
            //這里保存過期時間,為了給客戶短信通知,這個可以根據User_id去存儲哦 $redis->setex($userId,$expire,$tokenTime); //這里表示用戶已近開始打流了,這時候計算打流時間就可以了
            echo "Username and Password OK";
        }
        return true;

 


免責聲明!

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



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