すべてのプロダクト
Search
ドキュメントセンター

ApsaraVideo VOD:HLS 暗号化

最終更新日:Jan 30, 2026

HTTP Live Streaming (HLS) 暗号化は、AES-128 アルゴリズムを使用します。この方法はすべての HLS プレーヤーと互換性があり、キー管理とトークンサービスを使用してアクセス制御を行います。HLS 暗号化は、オンライン教育や限定コンテンツのストリーミングなど、高いセキュリティ要件が求められるシナリオで広く使用されています。このトピックでは、HLS 暗号化を使用して動画を暗号化し、再生のために復号する方法について説明します。

仕組み

ApsaraVideo VOD はエンベロープ暗号化を使用します。ご利用のサービスは Alibaba Cloud Key Management Service (KMS) を使用して、データキー (DK) とエンベロープデータキー (EDK) を生成します。DK を使用して動画を暗号化した後、暗号化された動画と EDK が保存されます。再生中、復号サービスは DK を取得して動画を復号します。

復号アドレスでセキュリティ認証を実行するために、M3U8 暗号化と書き換えを有効にして、HLS データアクセスプロセスに保護レイヤーを追加できます。デフォルトの書き換えパラメーターは MtsHlsUriToken です。M3U8 暗号化と書き換えを有効にする方法とその仕組みの詳細については、「M3U8 暗号化と書き換えの設定」をご参照ください。

前提条件

  • Alibaba Cloud 動画暗号化 (HLS 暗号化) は無料のサービスです。ただし、この機能を使用するには動画のトランスコーディングが必要です。トランスコーディング操作にはサービス料金が発生します。課金の詳細については、「メディアトランスコーディングの課金」をご参照ください。

  • ApsaraVideo VOD が有効化されていること。詳細については、「ApsaraVideo VOD の有効化」をご参照ください。

  • ApsaraVideo VOD に KMS へのアクセスに必要な権限が付与されていること。権限はクラウドリソースアクセス権限付与ページで付与できます。

  • ApsaraVideo VOD で高速化ドメイン名が設定されていること。詳細については、「高速化ドメイン名の追加」をご参照ください。

  • ApsaraVideo VOD のサーバーサイド SDK がインストールされていること。詳細については、「サーバーサイド SDK」をご参照ください。このトピックでは、Java 用 SDK を例として使用します。

用語

概念

説明

Resource Access Management (RAM)

ユーザー ID とリソースのアクセス権限を管理するために使用できる Alibaba Cloud サービスです。詳細については、「RAM とは」をご参照ください。

Key Management Service (KMS)

キー管理とデータ暗号化のためのワンストッププラットフォームです。シンプルで信頼性が高く、安全でコンプライアンスに準拠した暗号化保護と認証情報管理機能を提供します。詳細については、「KMS とは」をご参照ください。

データキー (DK)

データの暗号化に使用される平文キーです。詳細については、「用語」をご参照ください。

エンベロープデータキー (EDK)

エンベロープ暗号化を使用して保護された暗号文データキーです。詳細については、「用語」をご参照ください。

暗号化と復号のプロセス

アップロードと暗号化のプロセス

视频安全-HLS标准加密3

復号と再生のプロセス

M3U8 暗号化と書き換えが有効 (推奨)

视频安全-HLS标准加密6..png

M3U8 暗号化と書き換えが無効

视频安全-HLS标准加密2

動画の暗号化

  1. 動画をアップロードしてコールバックを受信する。

    HLS で暗号化されたビデオの自動トランスコードを防ぐには、ApsaraVideo VOD へのアップロード時に、組み込みのトランスコードなし テンプレートグループを使用してください。

    1. ApsaraVideo VOD コンソールを使用するか、API 操作を呼び出して動画をアップロードします。詳細については、「ApsaraVideo VOD コンソールを使用したメディアファイルのアップロード」および「メディアアップロード」をご参照ください。

    2. ApsaraVideo VOD のイベント通知を設定します。動画アップロード完了 のコールバックメッセージを受信すると、動画は ApsaraVideo VOD にアップロードされます。イベント通知の設定方法の詳細については、「イベント通知」をご参照ください。

  2. 暗号化サービスをセットアップする。

    1. サービスキーを作成する。

      サービスキーは KMS のプライマリ暗号化キーであり、標準暗号化キーを生成するために必要です。サービスキーを作成しない場合、GenerateDataKey 操作を呼び出してキーを生成する際にエラーが報告されます。

      1. ページの左上隅にあるリージョン ID をクリックして、サービスキーを作成するリージョンに切り替えます。

        説明

        サービスキーは、動画が保存されているオリジンサーバーと同じリージョンにある必要があります。たとえば、動画が中国 (上海) に保存されている場合、サービスキーも中国 (上海) で作成する必要があります。

        标准加密-服务地域

      2. ApsaraVideo VOD コンソールにログインします。左側のナビゲーションウィンドウで、設定の管理 > ApsaraVideo Media Processing の設定 > 標準暗号化 を選択します。

      3. [標準暗号化] ページで、[サービスキーの作成] をクリックします。

        サービスキーが作成されると、メッセージが表示されます。[キー情報] セクションでサービスキーを表示できます。

        説明

        サービスキーが作成されたことを示すメッセージが表示されてもサービスキーを表示できない場合は、サービスリンクロールが欠落している可能性があります。権限を再付与してロールを復元し、ページをリフレッシュしてサービスキーを表示できます。

    2. API 操作を呼び出してデータキーを生成する。

      GenerateDataKey 操作を呼び出して、DK と EDK を生成します。この操作にパラメーターを渡す必要はありません。呼び出しが成功すると、応答の `CiphertextBlob` は AES-128 形式の EDK になります。標準の暗号化とトランスコーディングのためにこの値をキャッシュする必要があります。応答の `Plaintext` は DK です。

  3. HLS 暗号化用のトランスコーディングテンプレートグループを作成する。

    HLS 暗号化プロセスには、組み込みの [トランスコードなし] テンプレートグループとカスタム HLS 暗号化トランスコーディングテンプレートグループの 2 つのトランスコーディングテンプレートグループが必要です。以下の手順では、カスタムグループの作成方法について説明します。

    1. ApsaraVideo VOD コンソールにログインします。左側のナビゲーションウィンドウで、設定の管理 > ApsaraVideo Media Processing の設定 > トランスコードテンプレートグループ を選択します。

    2. [トランスコーディングテンプレートグループ] ページで、HLS 暗号化用のテンプレートグループを作成します。

      カプセル化形式]を hls に設定します。[高度なパラメーター]セクションで、[ビデオの暗号化]を有効にして、[Alibaba Cloud Encryption]を選択します。他のパラメーターは必要に応じて設定できます。詳細については、「トランスコードテンプレート」をご参照ください。视频安全-HLS加密-控制台

    3. テンプレートが作成された後、[トランスコーディングテンプレートグループ] ページでトランスコーディングテンプレートグループの ID を表示できます。この ID は、後で HLS 暗号化とトランスコーディングを開始するときに必要になるため、保存してください。视频安全-HLS加密-控制台1

  4. HLS 暗号化とトランスコーディングを開始する。

    1. SubmitTranscodeJobs 操作を呼び出して、HLS 暗号化とトランスコーディングを開始します。

      クリックして Java サンプルコードを展開

      Java サンプルコードの以下のパラメーターは、要件に応じて変更する必要があります。

      パラメーター

      入力値

      request.setTemplateGroupId("")

      ステップ 3 で作成した HLS 暗号化用のトランスコーディングテンプレートグループの ID。

      request.setVideoId("")

      ステップ 1 でアップロードした暗号化対象の動画の ID。

      encryptConfig.put("CipherText","")

      ステップ 2 で返された CiphertextBlob の値。

      encryptConfig.put("DecryptKeyUri","")

      キー URI。キー URI は、復号サービスアドレスと CiphertextBlob 値の組み合わせです。たとえば、ローカルポートが 8099 の場合、キー URI は次のようになります。

      http://172.16.0.1:8099?CipherText=CiphertextBlobValue

      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.aliyuncs.DefaultAcsClient;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.profile.DefaultProfile;
      import com.aliyuncs.vod.model.v20170321.SubmitTranscodeJobsRequest;
      import com.aliyuncs.vod.model.v20170321.SubmitTranscodeJobsResponse;
      
      public class SubmitTranscodeJobs {
      
          // Alibaba Cloud アカウントの AccessKey ペアは、すべての API 操作を呼び出す権限を持っています。RAM ユーザーの AccessKey ペアを使用して API 操作を呼び出すか、日常の O&M を実行することを推奨します。
          // プロジェクトコードに AccessKey ID と AccessKey Secret をハードコーディングしないことを強く推奨します。そうしないと、AccessKey ペアが漏洩し、すべてのリソースのセキュリティが脅かされる可能性があります。
          // この例では、環境変数から AccessKey ペアを読み取って API アクセスを認証する方法を示します。コードを実行する前に、ALIBABA_CLOUD_ACCESS_KEY_ID および ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定してください。
          private static String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
          private static String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
      
          public static SubmitTranscodeJobsResponse submitTranscodeJobs(DefaultAcsClient client) throws Exception{
              SubmitTranscodeJobsRequest request = new SubmitTranscodeJobsRequest();
              request.setTemplateGroupId("");
              request.setVideoId("");
              JSONObject encryptConfig = new JSONObject();
              encryptConfig.put("CipherText","");
              encryptConfig.put("DecryptKeyUri","");
              encryptConfig.put("KeyServiceType","KMS");
              request.setEncryptConfig(encryptConfig.toJSONString());
              return client.getAcsResponse(request);
          }
      
          public static void main(String[] args) throws ClientException {
              String regionId = "cn-shanghai";  // ApsaraVideo VOD サービスが有効化されているリージョン。
              DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
              DefaultAcsClient client = new DefaultAcsClient(profile);
      
              SubmitTranscodeJobsResponse response;
              try {
                  response = submitTranscodeJobs(client);
                  System.out.println("RequestId is:"+response.getRequestId());
                  System.out.println("TranscodeTaskId is:"+response.getTranscodeTaskId());
                  System.out.println("TranscodeJobs is:"+ JSON.toJSON(response.getTranscodeJobs()));
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }       
    2. ApsaraVideo VOD のイベント通知を設定している場合、単一解像度動画のトランスコーディング完了 または 全解像度動画のトランスコーディング完了 のコールバックメッセージを受信すると、動画のトランスコーディングは完了です。

  5. HLS 暗号化の結果を表示する。

    トランスコーディングが完了した後、以下の 3 つの方法で標準暗号化が成功したかどうかを判断できます。

    • 方法 1: ApsaraVideo VOD コンソールにログインし、メディアファイル > [オーディオ/ビデオ] > 管理 > ビデオ URL を選択します。[ビデオ URL] ページで、ビデオにオリジナルの MP4 ファイルなどの複数のフォーマットの出力がある場合は、m3u8 ビデオストリームに 標準暗号化 というラベルが付いているかどうかを確認します。ラベルが表示されている場合、HLS 暗号化は成功です。ビデオセキュリティ - HLS 標準暗号化 5

    • 方法 2: 標準暗号化 を使用する M3U8 ファイルの URL をコピーし、curl -v "M3U8 ファイルの URL" コマンドを実行して M3U8 コンテンツを確認します。 コンテンツにキー URI="<標準暗号化のために渡す復号 URI で、DecryptKeyUri パラメーターの値です>" が含まれている場合、ビデオは HLS 暗号化によって保護されています。

    • 方法 3:GetTranscodeTask 操作を呼び出します。ステップ 4 で返された JobId パラメーターの値を渡します。返された TranscodeTemplateId パラメーターが ステップ 3 で作成したトランスコーディングテンプレートグループの ID であり、TranscodeJobStatus パラメーターが TranscodeSuccess である場合、HLS 暗号化は成功です。

HLS (M3U8) 暗号化と書き換え (推奨)

M3U8 暗号化と書き換え機能を有効にすると、システムは自動的に暗号化アルゴリズム、キー URI、認証パラメーターなどの暗号化パラメーターを HLS プロトコルのメディアプレイリスト (M3U8 ファイル) の #EXT-X-KEY タグに追加します。クライアントが書き換えられた M3U8 ファイルを解析すると、認証パラメーター付きのキー URI を使用して復号鍵をリクエストします。その後、クライアントはそのキーと指定されたアルゴリズムを使用して TS シャードを復号します。このプロセスにより、HLS ストリーミングメディアに暗号化されたアクセス保護が提供されます。

ステップ 1: 標準暗号化パラメーターのパススルーを有効にする

ApsaraVideo VOD コンソールで、HLS 標準暗号化パラメータのパススルー を有効にします。

HLS 暗号化のHLS 標準暗号化パラメータのパススルーを有効にすると、HLS 用の M3U8 ファイルを変更できます。この機能は、クライアントリクエストからのパラメーターを追加することにより、#EXT-X-KEY タグ内の URI を変更します。デフォルトのパラメーター名は MtsHlsUriToken です。

前提条件

オリジン間リソース共有 (CORS) が設定されていること。詳細については、「オリジン間リソース共有の設定」をご参照ください。

重要

この機能は現在 Alibaba Gov Cloud ではサポートされていません。

手順

  1. ApsaraVideo VOD コンソールにログインします。

  2. 左側のナビゲーションウィンドウで、設定の管理 をクリックします。

  3. [配信の高速化設定] > [ドメイン名] をクリックして、[ドメイン名] ページに移動します。

  4. 対象のドメイン名を見つけ、操作 列の [設定] をクリックします。

  5. ドメイン名のページの左側にあるナビゲーションウィンドウで、動画関連 をクリックします。

  6. 暗号化再生セクションで、HLS 標準暗号化パラメータのパススルー スイッチをオンにします。p181836

説明
  • この機能を有効にすると、HLS 暗号化パラメーターがパススルーされる際に、システムはトークン認証パラメーターを書き換えることでリクエストを認証します。書き換えられたパラメーター名は MtsHlsUriToken で、その値は test です。Alibaba Cloud CDN が再生のために動画を復号する際、M3U8 ファイルの #EXT-X-KEY タグの URI の末尾に MtsHlsUriToken=test が追加されます。

ステップ 2: MtsHlsUriToken パラメーターを含むリクエストを送信する

クライアントは、MtsHlsUriToken パラメーターを含むリクエストを CDN の POP (Point of Presence) に送信して、M3U8 ファイルにアクセスします。

MtsHlsUriToken を取得するには、ユーザートークンを発行するためのトークンサービスを構築する必要があります。このサービスが MtsHlsUriToken を生成します。

以下のコードで生成されるトークンが MtsHlsUriToken です。サンプルコードの以下のパラメーターは、要件に応じて変更する必要があります。

クリックして Java サンプルコードを展開

パラメーター

入力値

ENCRYPT_KEY

暗号鍵。16、24、または 32 文字のカスタム文字列。

INIT_VECTOR

暗号化オフセット。特殊文字を含まない 16 文字のカスタム文字列。

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

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;

public class PlayToken {
    // AES を使用してトークンを生成しない場合、以下のパラメーターは不要です。
    private static String ENCRYPT_KEY = ""; // 暗号鍵。16、24、または 32 文字のカスタム文字列。
    private static String INIT_VECTOR = ""; // 暗号化オフセット。特殊文字を含まない 16 文字のカスタム文字列。

    public static void main(String[] args) throws Exception {

        String serviceId = "12";
        PlayToken playToken = new PlayToken();
        String aesToken = playToken.generateToken(serviceId);
        //System.out.println("aesToken " + aesToken);
        //System.out.println(playToken.validateToken(aesToken));   // 復号検証部分。
    }
    /**
     * 渡されたパラメーターに基づいてトークンを生成します。
     * 注意:
     *  1. パラメーターには、サービスのユーザー ID、再生クライアントの種類、その他の情報を含めることができます。
     *  2. トークンは、トークン API が呼び出されたときに生成されます。
     * @param args
     * @return
     */
    public String generateToken(String... args) throws Exception {
        if (null == args || args.length <= 0) {
            return null;
        }
        String base = StringUtils.join(Arrays.asList(args), "_");
        // トークンを 30 秒後に有効期限切れに設定します。有効期限は調整可能です。
        long expire = System.currentTimeMillis() + 30000L;
        base += "_" + expire;   // カスタム文字列。ベース文字列の長さは 16 文字です。この例では、タイムスタンプが 13 文字、アンダースコア (_) が 1 文字を占めるため、さらに 2 文字を渡す必要があります。必要に応じて文字列全体を変更して、ベース文字列が 16、24、または 32 文字になるようにすることもできます。
        // トークンを生成します。
        String token = encrypt(base, ENCRYPT_KEY);  // arg1 は暗号化するカスタム文字列、arg2 は暗号鍵です。
        // トークンを保存します。これは復号時にトークンの有効性 (有効期限や使用回数など) を検証するために使用されます。
        saveToken(token);
        return token;
    }

    /**
     * トークンの有効性を検証します。
     * 注意:
     *  1. 復号 API が再生キーを返す前に、トークンの正当性と有効性を検証する必要があります。
     *  2. トークンの有効期限と有効使用回数の両方を検証することを強く推奨します。
     * @param token
     * @return
     * @throws Exception
     */
    public boolean validateToken(String token) throws Exception {
        if (null == token || "".equals(token)) {
            return false;
        }
        String base = decrypt(token,ENCRYPT_KEY); // arg1 は復号する文字列、arg2 は復号鍵です。
        // まず、トークンの有効期間を検証します。
        Long expireTime = Long.valueOf(base.substring(base.lastIndexOf("_") + 1));
        System.out.println("Time verification:" + expireTime);
        if (System.currentTimeMillis() > expireTime) {
            return false;
        }
        // データベースからトークン情報を取得して、その有効性を判断します。この部分はご自身で実装できます。
        TokenInfo dbToken = getToken(token);
        // トークンが既に使用されているかどうかを確認します。
        if (dbToken == null || dbToken.useCount > 0) {
            return false;
        }
        // ビジネス属性情報を取得して検証します。
        String businessInfo = base.substring(0, base.lastIndexOf("_"));
        String[] items = businessInfo.split("_");
        // ビジネス情報の正当性を検証します。この部分はご自身で実装できます。
        return validateInfo(items);
    }
    /**
     * トークンをデータベースに保存します。
     * この部分はご自身で実装できます。
     *
     * @param token
     */
    public void saveToken(String token) {
        //TODO: トークンを保存します。
    }
    /**
     * トークンをクエリします。
     * この部分はご自身で実装できます。
     *
     * @param token
     */
    public TokenInfo getToken(String token) {
        //TODO: データベースからトークン情報を取得して、その有効性と正当性を検証します。
        return null;
    }
    /**
     * ビジネス情報の有効性を検証します。この部分はご自身で実装できます。
     *
     * @param infos
     * @return
     */
    public boolean validateInfo(String... infos) {
        //TODO: UID が有効かどうかなど、情報の有効性を検証します。
        return true;
    }
    /**
     * AES 暗号化を使用してトークンを生成します。
     *
     * @param encryptStr  暗号化する文字列。
     * @param encryptKey  暗号鍵。
     * @return
     * @throws Exception
     */
    public String encrypt(String encryptStr, String encryptKey) throws Exception {
        IvParameterSpec e = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
        SecretKeySpec skeySpec = new SecretKeySpec(encryptKey.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, e);
        byte[] encrypted = cipher.doFinal(encryptStr.getBytes());
        return Base64.encodeBase64String(encrypted);
    }
    /**
     * AES を使用してトークンを復号します。
     *
     * @param encryptStr  復号する文字列。
     * @param decryptKey  復号鍵。
     * @return
     * @throws Exception
     */
    public String decrypt(String encryptStr, String decryptKey) throws Exception {

        IvParameterSpec e = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
        SecretKeySpec skeySpec = new SecretKeySpec(decryptKey.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, e);

        byte[] encryptByte = Base64.decodeBase64(encryptStr);
        byte[] decryptByte = cipher.doFinal(encryptByte);
        return new String(decryptByte);
    }
    /**
     * トークン情報。より多くの情報を提供できます。これは参考例です。
     */
    class TokenInfo {
        // トークンが使用できる回数。分散環境では、同期の問題に注意してください。
        int useCount;
        // トークンの内容。
        String token;
    }}
                        
説明

上記のコードはオープンソースの例であり、SDK やサービスコードは含まれていません。要件に基づいて設定および調整する必要があります。

ステップ 3: ファイルを復号して再生する

CDN の POP がクライアントからリクエストを受信した後、認証が成功すると動画を復号して再生します。

ステップ 2 で生成された MtsHlsUriToken パラメーターの値が test の場合、CDN が再生のために動画を復号する際に、M3U8 ファイルの #EXT-X-KEY タグの URI の末尾に MtsHlsUriToken=test が追加されます。

認証ロジックはご自身で実装する必要があります。詳細については、「動画の再生」の M3U8 暗号化と書き換えが有効な場合の復号サービスのサンプルコードをご参照ください。

動画の再生

M3U8 暗号化と書き換えが有効 (推奨)

  1. 復号サービスをセットアップする。

    動画を復号するためにローカル HTTP サービスをセットアップします。

    Decrypt 操作を呼び出してキーを復号します。応答の PlainText はデータキー (DK) です。この DK は、GenerateDataKey 操作によって返される PlainText の Base64 デコード済みデータです。

    復号アドレスでセキュリティ認証を実行するために、M3U8 暗号化と書き換えを有効にできます。これにより、HLS データアクセスプロセスに保護レイヤーが追加されます。デフォルトの書き換えパラメーターは MtsHlsUriToken です。復号サービスをセットアップするコードは、M3U8 暗号化と書き換えを有効にするかどうかによって異なります。

    クリックして Java サンプルコードを展開

    Java サンプルコードの以下のパラメーターは、要件に応じて変更する必要があります。

    パラメーター

    入力値

    region

    リージョン ID。KMS と ApsaraVideo VOD は同じリージョンにある必要があります。たとえば、中国 (上海) で KMS と ApsaraVideo VOD を使用する場合、このパラメーターを cn-shanghai に設定します。他のリージョンの ID の詳細については、「ApsaraVideo VOD のリージョン ID」をご参照ください。

    AccessKey

    Alibaba Cloud アカウントまたは RAM ユーザーの AccessKey ID と AccessKey Secret。AccessKey ペアの取得方法の詳細については、「AccessKey ペアの作成」をご参照ください。

    httpserver

    サービスを開始するために使用するポート番号。

    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.ProtocolType;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyRequest;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyResponse;
    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 へのアクセスに使用される AccessKey ペア。
            // Alibaba Cloud アカウントの AccessKey ペアは、すべての API 操作を呼び出す権限を持っています。RAM ユーザーの AccessKey ペアを使用して API 操作を呼び出すか、日常の O&M を実行することを推奨します。
            // プロジェクトコードに AccessKey ID と AccessKey Secret をハードコーディングしないことを強く推奨します。そうしないと、AccessKey ペアが漏洩し、すべてのリソースのセキュリティが脅かされる可能性があります。
            // この例では、環境変数から AccessKey ペアを読み取って API アクセスを認証する方法を示します。コードを実行する前に、ALIBABA_CLOUD_ACCESS_KEY_ID および ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定してください。
            String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
            String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
            client = new DefaultAcsClient(DefaultProfile.getProfile(region, accessKeyId, accessKeySecret));
        }
        /**
         * 注意:
         * 1. 復号リクエストを受信し、暗号文キーとユーザートークンを取得します。
         * 2. KMS 復号操作を呼び出して、平文キーを取得します。
         * 3. Base64 デコードされた平文キーを返します。
         */
        public class HlsDecryptHandler implements HttpHandler {
            /**
             * 復号リクエストを処理します。
             * @param httpExchange
             * @throws IOException
             */
            public void handle(HttpExchange httpExchange) throws IOException {
                String requestMethod = httpExchange.getRequestMethod();
                if ("GET".equalsIgnoreCase(requestMethod)) {
                    // トークンの有効性を検証します。
                    String token = getMtsHlsUriToken(httpExchange);
                    boolean validRe = validateToken(token);
                    if (!validRe) {
                        return;
                    }
                    // URL から暗号文キーを取得します。
                    String ciphertext = getCiphertext(httpExchange);
                    if (null == ciphertext)
                        return;
                    // KMS からキーを復号し、Base64 デコードします。
                    byte[] key = decrypt(ciphertext);
                    // ヘッダーを設定します。
                    setHeader(httpExchange, key);
                    // Base64 デコードされたキーを返します。
                    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 復号操作を呼び出してキーを復号し、平文を Base64 デコードします。
             * @param ciphertext
             * @return
             */
            private byte[] decrypt(String ciphertext) {
                DecryptKMSDataKeyRequest request = new DecryptKMSDataKeyRequest();
                request.setCipherText(ciphertext);
                request.setProtocol(ProtocolType.HTTPS);
                try {
                    DecryptKMSDataKeyResponse response = client.getAcsResponse(request);
                    String plaintext = response.getPlaintext();
                    System.out.println("PlainText: " + plaintext);
                    // 注意: プレーンテキストは Base64 デコードされている必要があります。
                    return Base64.decodeBase64(plaintext);
                } catch (ClientException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            /**
             * 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;
                }
            }
            
              /**
             * トークンの有効性を検証します。これは M3U8 暗号化と書き換えに必要です。
             * @param token
             * @return
             */
            private boolean validateToken(String token) {
                if (null == token || "".equals(token)) {
                    return false;
                }
                //TODO: トークンの有効性検証を実装します。
                return true;
            }
            /**
             * トークンパラメーターを取得します。これは M3U8 暗号化と書き換えに必要です。
             *
             * @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();
            // リスニングポートはカスタマイズできます。同時に最大 30 のリクエストを受け入れることができます。
            HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8099), 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();
        }}
  2. 動画の再生 URL と認証情報を取得する。

    GetVideoPlayAuth 操作を呼び出して再生認証情報を取得するか、GetPlayInfo 操作を呼び出して再生 URL を取得します。

  3. 暗号化された動画を再生する。

    HLS 暗号化はすべての HLS プレーヤーと互換性があります。自社開発のプレーヤーまたは ApsaraVideo Player を使用して、暗号化された動画を再生できます。

    ApsaraVideo Player を使用する場合、再生前に ApsaraVideo Player が要求するトークンと認証情報を取得する必要があります。詳細については、「暗号化された動画の再生」をご参照ください。ApsaraVideo Player 以外のプレーヤーを使用する場合は、再生ロジックを実装する必要があります。

    以下のセクションでは、テスト再生に ApsaraVideo Player を使用する際の内部プロセスについて説明します。

    M3U8 暗号化と書き換えが有効 (推奨)

    プロセス

    • プレーヤーは M3U8 ファイルの EXT-X-KEY タグを解析して、復号キー URI を取得します。この URI は、EncryptConfigDecryptKeyUri パラメーターの値に対応します。

    • 不正アクセスを防ぐため、プレーヤーは復号 API をリクエストする際に、MtsHlsUriToken パラメーターを使用して渡される認証情報を含める必要があります。

    • プレーヤーは自動的に復号 API をリクエストしてキーを取得し、暗号化された TS ファイルを復号してから再生を開始します。

    • 動画の再生 URL は https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8 です。リクエストには MtsHlsUriToken パラメーターを含める必要があります。

    • 最終的なリクエスト URL は https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8?MtsHlsUriToken=<token> です。

    • 復号アドレスは https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT**** です。

    • 最終的な復号リクエスト URL は https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****&MtsHlsUriToken=<issued_token> です。

M3U8 暗号化と書き換えが無効

  1. 復号サービスをセットアップする。

    動画を復号するためにローカル HTTP サービスをセットアップします。

    Decrypt 操作を呼び出してキーを復号します。応答の PlainText はデータキー (DK) です。この DK は、GenerateDataKey 操作によって返される PlainText の Base64 デコード済みデータです。

    以下に例を示します。

    クリックして Java サンプルコードを展開

    Java サンプルコードの以下のパラメーターは、要件に応じて変更する必要があります。

    パラメーター

    入力値

    region

    リージョン ID。KMS と ApsaraVideo VOD は同じリージョンにある必要があります。たとえば、中国 (上海) で KMS と ApsaraVideo VOD を使用する場合、このパラメーターを cn-shanghai に設定します。他のリージョンの ID の詳細については、「ApsaraVideo VOD のリージョン ID」をご参照ください。

    AccessKey

    Alibaba Cloud アカウントまたは RAM ユーザーの AccessKey ID と AccessKey Secret。AccessKey ペアの取得方法の詳細については、「AccessKey ペアの作成」をご参照ください。

    httpserver

    サービスを開始するために使用するポート番号。

    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.ProtocolType;
    import com.aliyuncs.profile.DefaultProfile;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyRequest;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyResponse;
    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 HlsDecryptServerNoToken {
    
        private static DefaultAcsClient client;
        static {
            // KMS のリージョン。動画が保存されているリージョンと同じである必要があります。
            String region = "cn-beijing";
            // KMS へのアクセスに使用される AccessKey ペア。
            // Alibaba Cloud アカウントの AccessKey ペアは、すべての API 操作を呼び出す権限を持っています。RAM ユーザーの AccessKey ペアを使用して API 操作を呼び出すか、日常の O&M を実行することを推奨します。
            // プロジェクトコードに AccessKey ID と AccessKey Secret をハードコーディングしないことを強く推奨します。そうしないと、AccessKey ペアが漏洩し、すべてのリソースのセキュリティが脅かされる可能性があります。
            // この例では、環境変数から AccessKey ペアを読み取って API アクセスを認証する方法を示します。コードを実行する前に、ALIBABA_CLOUD_ACCESS_KEY_ID および ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定してください。
            String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
            String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
            client = new DefaultAcsClient(DefaultProfile.getProfile(region, accessKeyId, accessKeySecret));
        }
        /**
         * 注意:
         * 1. 復号リクエストを受信し、暗号文キーとトークンを取得します。
         * 2. KMS 復号操作を呼び出して、平文キーを取得します。
         * 3. Base64 デコードされた平文キーを返します。
         */
        public class HlsDecryptHandler implements HttpHandler {
            /**
             * 復号リクエストを処理します。
             * @param httpExchange
             * @throws IOException
             */
            public void handle(HttpExchange httpExchange) throws IOException {
                String requestMethod = httpExchange.getRequestMethod();
                if ("GET".equalsIgnoreCase(requestMethod)) {
    
                    // URL から暗号文キーを取得します。
                    String ciphertext = getCiphertext(httpExchange);
                    System.out.println(ciphertext);
                    if (null == ciphertext)
                        return;
                    // KMS からキーを復号し、Base64 デコードします。
                    byte[] key = decrypt(ciphertext);
                    // ヘッダーを設定します。
                    setHeader(httpExchange, key);
                    // Base64 デコードされたキーを返します。
                    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 復号操作を呼び出してキーを復号し、平文を Base64 デコードします。
             * @param ciphertext
             * @return
             */
            private byte[] decrypt(String ciphertext) {
    
                DecryptKMSDataKeyRequest request = new DecryptKMSDataKeyRequest();
                request.setCipherText(ciphertext);
                request.setProtocol(ProtocolType.HTTPS);
                try {
                    DecryptKMSDataKeyResponse response = client.getAcsResponse(request);
                    String plaintext = response.getPlaintext();
                    System.out.println("PlainText: " + plaintext);
                    // 注意: プレーンテキストは Base64 デコードされている必要があります。
                    return Base64.decodeBase64(plaintext);
                } catch (ClientException e) {
                    e.printStackTrace();
                    return null;
                }
            }
    
            /**
             * 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;
                }
            }
        }
    
        /**
         * サービスを開始します。
         *
         * @throws IOException
         */
        private void serviceBootStrap() throws IOException {
            HttpServerProvider provider = HttpServerProvider.provider();
            // リスニングポートはカスタマイズできます。同時に最大 30 のリクエストを受け入れることができます。
            HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8099), 30);
            httpserver.createContext("/", new HlsDecryptHandler());
            httpserver.start();
            System.out.println("hls decrypt server started");
        }
        public static void main(String[] args) throws IOException {
            HlsDecryptServerNoToken server = new HlsDecryptServerNoToken();
            server.serviceBootStrap();
        }}
    
  2. 動画の再生 URL と認証情報を取得する。

    GetVideoPlayAuth 操作を呼び出して再生認証情報を取得するか、GetPlayInfo 操作を呼び出して再生 URL を取得します。

  3. 暗号化された動画を再生する。

    HLS 暗号化はすべての HLS プレーヤーと互換性があります。自社開発のプレーヤーまたは ApsaraVideo Player を使用して、暗号化された動画を再生できます。

    ApsaraVideo Player を使用する場合、再生前に ApsaraVideo Player が要求するトークンと認証情報を取得する必要があります。詳細については、「暗号化された動画の再生」をご参照ください。ApsaraVideo Player 以外のプレーヤーを使用する場合は、再生ロジックを実装する必要があります。

    以下のセクションでは、テスト再生に ApsaraVideo Player を使用する際の内部プロセスについて説明します。

    M3U8 暗号化と書き換えが無効

    プロセス

    • プレーヤーは M3U8 ファイルの EXT-X-KEY タグを解析して、復号キー URI を取得します。この URI は、EncryptConfigDecryptKeyUri パラメーターの値に対応します。

    • プレーヤーは自動的に復号 API をリクエストしてキーを取得し、暗号化された TS ファイルを復号してから再生を開始します。

    • 動画の再生 URL は https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8 です。

    • 最終的なリクエスト URL は https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8 です。

    • 復号アドレスは https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT**** です。

    • 最終的な復号リクエスト URL は https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT**** です。

関連ドキュメント