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

ApsaraVideo VOD:HLS 暗号化

最終更新日:Jul 11, 2026

HLS 暗号化は AES-128 を使用しており、すべての HLS プレーヤーで動作します。キー管理やトークンサービスと組み合わせることで、オンライン教育や独占コンテンツのストリーミングなど、高セキュリティが求められるシナリオに適しています。

仕組み

ApsaraVideo VOD は、エンベロープ暗号化を使用します。サービスプロバイダーは、Alibaba Cloud Key Management Service (KMS) を使用してデータキー (DK) とエンベロープ化されたデータキー (EDK) を生成します。DK が動画を暗号化し、EDK は動画と共に保存されます。再生時には、クライアントが復号サービスから DK を取得して動画を復号します。

復号 URL を保護するには、M3U8 暗号化と書き換えを有効にします。これにより、HLS データアクセスプロセスに保護レイヤーが追加されます。デフォルトの書き換えパラメーターは MtsHlsUriToken です。この機能を有効にする方法と仕組みについては、「M3U8 暗号化と書き換え」をご参照ください。

前提条件

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

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

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

  • ApsaraVideo VOD にアクセラレーションドメイン名が追加されていること。手順については、「アクセラレーションドメイン名の追加」をご参照ください。

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

主要な概念

概念

説明

Resource Access Management (RAM)

ユーザーアイデンティティを管理し、お客様のリソースへのアクセスを制御するための Alibaba Cloud サービスです。詳細については、「RAM とは」をご参照ください。

Key Management Service (KMS)

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

データキー (DK)

データを暗号化するために使用するプレーンテキストキーです。詳細については、「用語」をご参照ください。

エンベロープ化されたデータキー (EDK)

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

暗号化と復号のワークフロー

アップロードと暗号化のワークフロー

视频安全-HLS标准加密3

復号と再生のワークフロー

M3U8 書き換え:有効 (推奨)

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

M3U8 書き換え:無効

视频安全-HLS标准加密2

動画の暗号化

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

    HLS 暗号化に対応した動画が自動的にトランスコードされるのを防ぐには、ApsaraVideo VOD に動画をアップロードする際に、組み込みの [トランスコードなし] テンプレートグループを使用する必要があります。これにより、アップロード中の自動トランスコーディングが防止されます。

    1. ApsaraVideo VOD コンソールを使用して動画をアップロードする方法については、「ApsaraVideo VOD コンソールでのファイルのアップロード」をご参照ください。サーバー側 API を使用して動画をアップロードする方法については、「メディアアップロード」をご参照ください。

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

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

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

      サービスキーは KMS のプライマリ暗号化キーで、HLS 暗号化用のキーを生成するために使用されます。サービスキーを作成しない場合、GenerateKMSDataKey API はエラーを返します。

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

        説明

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

        利用可能なリージョンは、中国 (上海) 、中国 (北京) 、中国 (深圳) 、日本 (東京) 、シンガポール、インドネシア (ジャカルタ) 、インド (ムンバイ) 、ドイツ (フランクフルト) です。

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

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

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

        説明

        成功メッセージが表示されてもキーを表示できない場合、サービスリンクロールが見つからないことが原因と考えられます。ApsaraVideo VOD を 再承認 してロールを復元し、ページを更新してサービスキーを表示できます。

    2. API を呼び出してデータキー (DK) を生成します。

      GenerateKMSDataKey API を呼び出して、データキー (DK) とエンベロープ化されたデータキー (EDK) を生成します。パラメーターを渡す必要はありません。呼び出しが成功すると、レスポンスの Plaintext フィールドに DK が、CiphertextBlob フィールドに AES-128 形式の EDK が含まれます。HLS 暗号化トランスコーディングジョブのために CiphertextBlob の値をキャッシュします。

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

    HLS 暗号化プロセスには、組み込みの トランスコードなし テンプレートグループと、HLS 暗号化用のカスタムトランスコードテンプレートグループの 2 つのトランスコードテンプレートグループが必要です。カスタムトランスコードテンプレートグループを作成するには、次の手順を実行します。

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

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

      カプセル化形式hls に設定します。高度なパラメーター セクションで、ビデオの暗号化 を有効にし、Alibaba Cloud Encryption オプションを選択します。必要に応じて、その他のパラメーターを設定します。パラメーターの詳細については、「トランスコーディングテンプレート」をご参照ください。

    3. テンプレートグループが作成されたら、[トランスコードテンプレートグループ] ページの一覧で新しいテンプレートグループを見つけ、その ID を記録します。このテンプレートグループ ID は、暗号化設定に必要です。

  4. HLS 暗号化トランスコーディングジョブを送信します。

    1. SubmitTranscodeJobs API を呼び出して、HLS 暗号化トランスコーディングジョブを送信します。

      Java サンプルコード

      次の Java サンプルコードでは、要件に応じて次のパラメーターを変更してください。

      パラメーター

      request.setTemplateGroupId("")

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

      request.setVideoId("")

      手順 1 でアップロードした動画の ID。

      encryptConfig.put("CipherText","")

      手順 2 で返された CiphertextBlob の値。

      encryptConfig.put("DecryptKeyUri","")

      キー URI。この URI は、復号サービスの URL と 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 ユーザーを使用して API 操作を呼び出すか、日常的な O&M を実行することを推奨します。
          // AccessKey ID と AccessKey secret をプロジェクトコードにハードコーディングしないことを強く推奨します。ハードコーディングすると、AccessKey ペアが漏洩し、すべてのリソースのセキュリティが損なわれる可能性があります。
          // この例では、環境変数を使用して認証用の AccessKey ペアを取得する方法を示します。サンプルコードを実行する前に、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. イベント通知を設定している場合、単一解像度トランスコーディング完了またはトランスコード完了イベントのコールバックメッセージで、トランスコーディングジョブが完了したことが通知されます。

  5. HLS 暗号化の結果を検証します。

    トランスコーディングジョブが完了したら、次のいずれかの方法で暗号化を検証します。

    • 方法 1: ApsaraVideo VOD コンソールにログインします。[オーディオ/ビデオ] ファイルの詳細ページに移動し、 [動画 URL] タブをクリックします。動画 URL リストで、M3U8 出力ファイルの format 列に [HLS 暗号化] タグがあるかどうかを確認します。このタグが存在すれば、暗号化が成功したことを確認できます。

    • 方法 2: 標準暗号化 タグが付いている M3U8 ファイルの URL をコピーします。 curl -v "M3U8 ファイルの URL" コマンドを実行して M3U8 コンテンツを取得します。 コンテンツで次のキー情報を確認します: URI="<DecryptKeyUri パラメーター値として指定した復号 URI>"。 この情報が存在する場合、暗号化は成功です。

    • 方法 3: GetTranscodeTask API を呼び出して、 手順 4 で返された TranscodeTaskId パラメーターの値を渡します。レスポンスの TranscodeTemplateId の値が 手順 3 で作成したトランスコードテンプレートグループの ID と一致し、かつ TranscodeJobStatusTranscodeSuccess であれば、暗号化は成功です。

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

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

手順 1:HLS 暗号化のパラメーターパススルーの有効化

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

HLS 標準暗号化パラメータのパススルー を有効にすると、ApsaraVideo VOD はクライアントリクエストのパラメーターを #EXT-X-KEY タグの URI に追加して M3U8 ファイルを書き換えます。デフォルトのパラメーター名は MtsHlsUriToken です。

前提条件

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

重要

この機能は Alibaba Cloud Gov Cloud では利用できません。

操作手順

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

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

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

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

  5. ドメインの設定ページで、左側のナビゲーションペインの動画関連をクリックします。

  6. 暗号化再生セクションでは、HLS 標準暗号化パラメータのパススルー スイッチをオンにします。デフォルトでは、このスイッチはオフになっており、パラメーター名は MtsHlsUriToken です。

説明
  • この機能を有効にすると、ApsaraVideo VOD はトークンパラメーターを書き換えることで認証を処理します。書き換えられたパラメーターは MtsHlsUriToken で、その値は test です。復号再生中に、POP は M3U8 ファイルの #EXT-X-KEY タグ内の URI に MtsHlsUriToken=test を追加します。

手順 2:MtsHlsUriToken を含むリクエストの送信

M3U8 ファイルにアクセスするために、クライアントは MtsHlsUriToken パラメーターを含むリクエストを POP に送信します。

ユーザー向けに 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 = "";
    private static String INIT_VECTOR = "";
    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;   // 有効期限のタイムスタンプを文字列に結合します。
        // トークンを生成します。
        String token = encrypt(base, ENCRYPT_KEY);  // 'encryptStr' は暗号化するカスタム文字列、'encryptKey' は暗号化キーです。
        // 復号時に検証するためにトークンを保存します (有効期限や使用回数など)。
        saveToken(token);
        return token;
    }
    /**
     * トークンを検証します。
     * 注意:
     *  1. 復号サービスは、再生キーを返す前に、トークンの正当性と有効性を検証する必要があります。
     *  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); // 'encryptStr' は復号する文字列、'decryptKey' は復号キーです。
        // まず、トークンの有効期限を検証します。
        Long expireTime = Long.valueOf(base.substring(base.lastIndexOf("_") + 1));
        System.out.println("Time validation: " + 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:ファイルの復号と再生

クライアントからリクエストを受信すると、POP はリクエストを認証します。認証が成功すると、POP はファイルを復号して再生します。

ステップ 2 で生成された MtsHlsUriToken パラメーターの値が test の場合、POP は復号化再生時に、M3U8 ファイルの #EXT-X-KEY タグの URI に MtsHlsUriToken=test を追加します。

認証ロジックを実装する必要があります。参考として、「動画の再生」に記載の、M3U8 の暗号化と書き換えに関する復号サービスのサンプルコードをご参照ください。

動画の再生

M3U8 書き換えあり (推奨)

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

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

    DecryptKMSDataKey API を呼び出してデータキーを復号します。レスポンスに含まれるデータキー PlainText は、GenerateKMSDataKey API が返した PlainText の値を Base64 デコードしたものです。

    復号 URL を検証してセキュリティを強化するために、M3U8 の暗号化と書き換えを有効にします。この機能は、トークンをキーリクエスト URL に追加します。デフォルトのパラメーター名は MtsHlsUriToken です。復号サービスの実装は、この機能が有効になっているかどうかによって異なります。

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

    次の表に、サンプルコードでカスタマイズできるパラメーターを示します。

    パラメーター

    説明

    region

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

    AccessKey

    Alibaba Cloud アカウントまたは RAM ユーザーのアクセスキーペア (AccessKey ID および AccessKey Secret) です。詳細については、「アクセスキーペアの作成」をご参照ください。

    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 にアクセスするためのアクセスキーペア。
            // Alibaba Cloud アカウントのアクセスキーペアは、すべての API 操作に対する権限を持っています。API 操作の呼び出しや日常の O&M の実行には、RAM ユーザーを使用することを推奨します。
            // AccessKey ID と AccessKey Secret をプロジェクトコードにハードコーディングしないことを強く推奨します。ハードコーディングすると、アクセスキーペアが漏洩し、アカウント内のすべてのリソースのセキュリティが侵害されるおそれがあります。
            // この例では、環境変数からアクセスキーペアを読み取って 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 の復号 API を呼び出して、プレーンテキストキーを取得します。
         * 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 の復号 API を呼び出し、プレーンテキストを 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 API を呼び出して再生認証情報を取得するか、GetPlayInfo API を呼び出して再生 URL を取得します。

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

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

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

    次のセクションでは、ApsaraVideo Player の内部再生プロセスについて説明します。

    M3U8 書き換えあり (推奨)

    ワークフロー

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

    • 不正アクセスを制限するために、プレーヤーは復号エンドポイントへのリクエストに認証情報 (MtsHlsUriToken パラメーターで渡される) を含める必要があります。

    • プレーヤーは、復号エンドポイントに自動的にリクエストしてキーを取得し、TS ファイルを復号してから動画を再生します。

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

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

    • 復号 URL: https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****

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

M3U8 書き換えなし

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

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

    DecryptKMSDataKey API を呼び出してデータキーを復号します。レスポンスに含まれるデータキー PlainText は、GenerateKMSDataKey API が返した PlainText の値を Base64 デコードしたものです。

    例:

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

    次の表に、サンプルコードでカスタマイズできるパラメーターを示します。

    パラメーター

    説明

    region

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

    AccessKey

    Alibaba Cloud アカウントまたは RAM ユーザーのアクセスキーペア (AccessKey ID および AccessKey Secret) です。詳細については、「アクセスキーペアの作成」をご参照ください。

    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-shanghai";
            // KMS にアクセスするためのアクセスキーペア。
            // Alibaba Cloud アカウントのアクセスキーペアは、すべての API 操作に対する権限を持っています。API 操作の呼び出しや日常の O&M の実行には、RAM ユーザーを使用することを推奨します。
            // AccessKey ID と AccessKey Secret をプロジェクトコードにハードコーディングしないことを強く推奨します。ハードコーディングすると、アクセスキーペアが漏洩し、アカウント内のすべてのリソースのセキュリティが侵害されるおそれがあります。
            // この例では、環境変数からアクセスキーペアを読み取って 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 の復号 API を呼び出して、プレーンテキストキーを取得します。
         * 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 の復号 API を呼び出し、プレーンテキストを 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 API を呼び出して再生認証情報を取得するか、GetPlayInfo API を呼び出して再生 URL を取得します。

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

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

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

    次のセクションでは、ApsaraVideo Player の内部再生プロセスについて説明します。

    M3U8 書き換えなし

    ワークフロー

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

    • プレーヤーは、復号エンドポイントに自動的にリクエストしてキーを取得し、TS ファイルを復号してから動画を再生します。

    • 再生 URL: https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8

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

    • 復号 URL: https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****

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

関連ドキュメント