天天看點

視訊點播視訊加密流程解決方案

業務場景

視訊點播視訊加密流程解決方案

目前阿裡雲視訊點播服務有兩種加密方式:1、阿裡雲私有加密;(目前移動端H5相容性不好,H5僅支援Android的Chrome浏覽器)2、HLS标準加密;(支援H5)

移動端以及PC相容情況:

視訊點播視訊加密流程解決方案

解決方案

1、阿裡雲私有加密

1)加密檔案生成,轉碼模闆處勾選“HLS加密”即可。

視訊點播視訊加密流程解決方案
生成之後的加密檔案是下面的樣式:
視訊點播視訊加密流程解決方案
同樣也可以通過curl去檢視您的視訊是否是阿裡雲私有加密,curl出來的結果是URI=xxx則為阿裡雲私有加密視訊
視訊點播視訊加密流程解決方案

2)阿裡雲私有加密視訊播放,私有加密的播放需要滿足兩個條件:1、使用阿裡雲提供的播放器;(目前有web、Android以及iOS)2、使用videoID+STS或者videoID+playauth方式播放。

web demo:

https://player.alicdn.com/aliplayer/setting/setting.html android以及iOS demo: https://help.aliyun.com/document_detail/51992.html

2、HLS标準加密

1)生成HLS标準加密視訊,目前生成HLS标準加密的視訊隻能通過API接口或者SDK進行處理。(也就是隻能代碼生成,無法直接使用控制台)

邏輯主要是:

視訊點播視訊加密流程解決方案
1、建立加密轉碼模闆
視訊點播視訊加密流程解決方案

2、RAM授權

使用RAM服務給視訊點播授權通路業務方秘鑰管理服務(KMS)的權限

視訊點播視訊加密流程解決方案

3、建立Service Key(KMS控制台建立即可)

4、送出加密轉碼:

1)通過接口:GenerateDataKey生成明文秘鑰和密文秘鑰之後,再送出轉碼作業;(EncryptConfig裡寫HLS标準加密資訊)

GenerateDataKey:

https://help.aliyun.com/document_detail/28948.html 送出轉碼作業接口: https://help.aliyun.com/document_detail/68570.html

2)直接使用送出轉碼作業是SDK demo(推薦使用)

以Java為例子:

https://help.aliyun.com/document_detail/98672.html

隻需要确認AK、SK、Service Key以及DecryptKeyUri正确即可

最終生成的HLS标準加密的視訊:

視訊點播視訊加密流程解決方案
通過curl進行驗證,得到的URI是 http:// 解密服務位址/xxx?Ciphertext=xxx 這樣的連接配接,則表示加密成功了。
視訊點播視訊加密流程解決方案

5、解密HLS标準加密視訊

1、談到解密,大家會比較關心一個令牌HlsMtsToken,這個其實是一個附件的選項。(可有可無)舉個例子:

我生成的加密位址是:

https://vod.xxxx.cn/8e1f0d9295cf41989a837f4aaab7a813/87ba78922d59fe6cba843e48b5ccb659-hd-encrypt-stream.m3u8 如果我的伺服器需要需要有個校驗值的話,就可以寫成: https://vod.xxxx.cn/8e1f0d9295cf41989a837f4aaab7a813/87ba78922d59fe6cba843e48b5ccb659-hd-encrypt-stream.m3u8?MtsHlsUriToken=xxxx 注意:MtsHlsUriToken=xxxx這個是解密伺服器自己判斷進行校驗的,但是需要送出工單給阿裡雲的工程師,配置,請求解密URI的時候,帶上這個參數。
視訊點播視訊加密流程解決方案

2、解密伺服器搭建

以Java為例子,如果是其他語言的話,按照下述的步驟寫就好。

import com.aliyuncs.DefaultAcsClient;

import com.aliyuncs.exceptions.ClientException;

import com.aliyuncs.http.ProtocolType;

import com.aliyuncs.kms.model.v20160120.DecryptRequest;

import com.aliyuncs.kms.model.v20160120.DecryptResponse;

import com.aliyuncs.profile.DefaultProfile;

import com.sun.net.httpserver.Headers;

import com.sun.net.httpserver.HttpExchange;

import com.sun.net.httpserver.HttpHandler;

import com.sun.net.httpserver.HttpServer;

import com.sun.net.httpserver.spi.HttpServerProvider;

import org.apache.commons.codec.binary.Base64;

import java.io.IOException;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.InetSocketAddress;

import java.net.URI;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class HlsDecryptServer {

private static DefaultAcsClient client;
static {
    //KMS的區域,必須與視訊對應區域
    String region = "<視訊對應區域>";
    //通路KMS的授權AK資訊
    String accessKeyId = "<您使用的AccessKeyId>";
    String accessKeySecret = "<您使用的AccessKeySecrect>";
    client = new DefaultAcsClient(DefaultProfile.getProfile(region, accessKeyId, accessKeySecret));
}
/**
 * 說明:
 * 1、接收解密請求,擷取密文秘鑰和令牌Token
 * 2、調用KMS decrypt接口擷取明文秘鑰
 * 3、将明文秘鑰base64decode傳回
 */
public class HlsDecryptHandler implements HttpHandler {
    /**
     * 處了解密請求
     * @param httpExchange
     * @throws IOException
     */
    public void handle(HttpExchange httpExchange) throws IOException {
        String requestMethod = httpExchange.getRequestMethod();
        if ("GET".equalsIgnoreCase(requestMethod)) {
            //校驗token的有效性
            String token = getMtsHlsUriToken(httpExchange);
            boolean validRe = validateToken(token);
            if (!validRe) {
                return;
            }
            //從URL中取得密文密鑰
            String ciphertext = getCiphertext(httpExchange);
            if (null == ciphertext)
                return;
            //從KMS中解密出來,并Base64 decode
            byte[] key = decrypt(ciphertext);
            //設定header
            setHeader(httpExchange, key);
            //傳回base64decode之後的密鑰
            OutputStream responseBody = httpExchange.getResponseBody();
            responseBody.write(key);
            responseBody.close();
        }
    }
    private void setHeader(HttpExchange httpExchange, byte[] key) throws IOException {
        Headers responseHeaders = httpExchange.getResponseHeaders();
        responseHeaders.set("Access-Control-Allow-Origin", "*");
        httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, key.length);
    }
    /**
     * 調用KMS decrypt接口解密,并将明文base64decode
     * @param ciphertext
     * @return
     */
    private byte[] decrypt(String ciphertext) {
        DecryptRequest request = new DecryptRequest();
        request.setCiphertextBlob(ciphertext);
        request.setProtocol(ProtocolType.HTTPS);
        try {
            DecryptResponse response = client.getAcsResponse(request);
            String plaintext = response.getPlaintext();
            //注意:需要base64 decode
            return Base64.decodeBase64(plaintext);
        } catch (ClientException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 校驗令牌有效性
     * @param token
     * @return
     */
    private boolean validateToken(String token) {
        if (null == token || "".equals(token)) {
            return false;
        }
        //TODO 業務方實作令牌有效性校驗
        return true;
    }
    /**
     * 從URL中擷取密文秘鑰參數
     * @param httpExchange
     * @return
     */
    private String getCiphertext(HttpExchange httpExchange) {
        URI uri = httpExchange.getRequestURI();
        String queryString = uri.getQuery();
        String pattern = "Ciphertext=(\\w*)";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(queryString);
        if (m.find())
            return m.group(1);
        else {
            System.out.println("Not Found Ciphertext Param");
            return null;
        }
    }
    /**
     * 擷取Token參數
     *
     * @param httpExchange
     * @return
     */
    private String getMtsHlsUriToken(HttpExchange httpExchange) {
        URI uri = httpExchange.getRequestURI();
        String queryString = uri.getQuery();
        String pattern = "MtsHlsUriToken=(\\w*)";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(queryString);
        if (m.find())
            return m.group(1);
        else {
            System.out.println("Not Found MtsHlsUriToken Param");
            return null;
        }
    }
}
/**
 * 服務啟動
 *
 * @throws IOException
 */
private void serviceBootStrap() throws IOException {
    HttpServerProvider provider = HttpServerProvider.provider();
    //監聽端口9999,能同時接受30個請求
    HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(9999), 30);
    httpserver.createContext("/", new HlsDecryptHandler());
    httpserver.start();
    System.out.println("hls decrypt server started");
}
public static void main(String[] args) throws IOException {
    HlsDecryptServer server = new HlsDecryptServer();
    server.serviceBootStrap();
}           

}

繼續閱讀