署名を生成する

このガイドでは、署名の作成方法と、署名の必須フィールドとオプションフィールドについて説明します。

署名を作成するには、署名する文字列を作成します。このガイドでは、これを署名付き値と呼びます。署名付き値には、保護するコンテンツ、署名付き値の有効期限などを記述するパラメータが含まれます。

署名付き値は、署名文字列の作成時に使用します。署名文字列は、署名付き値の非対称鍵 Ed25519 署名など、署名のパラメータをコンポーズして作成します。

Media CDN は、最終的な署名を使用してコンテンツを保護します。

サポートされている署名形式

Media CDN は、次の署名付きリクエスト形式をサポートしています。

形式 動作
クエリ パラメータ(正確な URL)

正確な URL: 特定の URL へのアクセス権を付与する場合に使用します。

Exact:

https://media.example.com/content/manifest.m3u8?
Expires=EXPIRATION
&KeyName=KEY_NAME
&Signature=SIGNATURE

クエリ パラメータ(URL プレフィックス) URLPrefix を指定すると、接頭辞に署名して、プレーヤーまたはマニフェスト生成内の複数の URL に同じクエリ パラメータを追加できます。

署名する書類:

URLPrefix=PREFIX
&Expires=EXPIRATION
&KeyName=KEY_NAME
&Signature=SIGNATURE

PREFIX は、スキーム、ホスト、部分パスなどのアクセスを許可する接頭辞に置き換えます。

経路コンポーネント

接頭辞: "/edge-cache-token=[...]" コンポーネントの前に接頭辞が付いた任意の URL へのアクセスを許可します。

これにより、サブリソースを取得するときに、相対マニフェスト URL が署名付き URL コンポーネントを自動的に継承できるようになります。

https://media.example.com/video/edge-cache-token=Expires=EXPIRATION
&KeyName=KEY_NAME
&Signature=SIGNATURE/manifest_12382131.m3u8
署名付き Cookie 接頭辞: Cookie は、署名付き URLPrefix 値で指定された接頭辞を持つ任意の URL へのアクセスを許可します。

Edge-Cache-Cookie:

URLPrefix=PREFIX:
Expires=EXPIRATION:
KeyName=KEY_NAME:
Signature=SIGNATURE

署名の作成

  1. 必須署名フィールドと必要なオプション署名フィールドを含む文字列を連結して、署名付き値を作成します。

    指定する場合は、URLPrefix を最初に配置し、ExpiresKeyName、オプションのパラメータをその後に配置する必要があります。

    各フィールドとパラメータは次のように区切ります。

    • Cookie の場合は、コロン(:)文字を使用します。
    • クエリ パラメータとパス コンポーネントには、アンパサンド(&)文字を使用します。
  2. 署名付き値に Ed25519 署名を付加します。

  3. フィールド区切り文字(: または &)を追加し、その後に Signature= と Ed25519 署名を文字列の末尾に追加します。

署名付き URL を作成する

次のコードサンプルは、署名付き URL をプログラムで作成する方法を示しています。

Go

Media CDN に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。 詳細については、ローカル開発環境の認証を設定するをご覧ください。

import (
	"crypto/ed25519"
	"encoding/base64"
	"fmt"
	"io"
	"strings"
	"time"
)

// signURL prints the signed URL string for the specified URL and configuration.
func signURL(w io.Writer, url, keyName string, privateKey []byte, expires time.Time) error {
	// url := "http://example.com"
	// keyName := "your_key_name"
	// privateKey := "[]byte{34, 31, ...}"
	// expires := time.Unix(1558131350, 0)

	sep := '?'
	if strings.ContainsRune(url, '?') {
		sep = '&'
	}
	toSign := fmt.Sprintf("%s%cExpires=%d&KeyName=%s", url, sep, expires.Unix(), keyName)
	sig := ed25519.Sign(privateKey, []byte(toSign))

	fmt.Fprintf(w, "%s&Signature=%s", toSign, base64.RawURLEncoding.EncodeToString(sig))

	return nil
}

Python

Media CDN に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。 詳細については、ローカル開発環境の認証を設定するをご覧ください。

import base64
import datetime

import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519


from six.moves import urllib

def sign_url(
    url: str, key_name: str, base64_key: str, expiration_time: datetime.datetime
) -> str:
    """Gets the Signed URL string for the specified URL and configuration.

    Args:
        url: URL to sign as a string.
        key_name: name of the signing key as a string.
        base64_key: signing key as a base64 encoded byte string.
        expiration_time: expiration time as a UTC datetime object.

    Returns:
        Returns the Signed URL appended with the query parameters based on the
        specified configuration.
    """
    stripped_url = url.strip()
    parsed_url = urllib.parse.urlsplit(stripped_url)
    query_params = urllib.parse.parse_qs(parsed_url.query, keep_blank_values=True)
    epoch = datetime.datetime.utcfromtimestamp(0)
    expiration_timestamp = int((expiration_time - epoch).total_seconds())
    decoded_key = base64.urlsafe_b64decode(base64_key)

    url_pattern = "{url}{separator}Expires={expires}&KeyName={key_name}"

    url_to_sign = url_pattern.format(
        url=stripped_url,
        separator="&" if query_params else "?",
        expires=expiration_timestamp,
        key_name=key_name,
    )

    digest = ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key).sign(
        url_to_sign.encode("utf-8")
    )
    signature = base64.urlsafe_b64encode(digest).decode("utf-8")
    signed_url = "{url}&Signature={signature}".format(
        url=url_to_sign, signature=signature
    )

    return signed_url

署名付き URL の接頭辞を作成する

次のコードサンプルは、署名付き URL 接頭辞をプログラムで作成する方法を示しています。

Go

Media CDN に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。 詳細については、ローカル開発環境の認証を設定するをご覧ください。

import (
	"crypto/ed25519"
	"encoding/base64"
	"fmt"
	"io"
	"strings"
	"time"
)

// signURLPrefix prints the signed URL string for the specified URL prefix and configuration.
func signURLPrefix(w io.Writer, urlPrefix, keyName string, privateKey []byte, expires time.Time) error {
	// urlPrefix := "https://examples.com"
	// keyName := "your_key_name"
	// privateKey := "[]byte{34, 31, ...}"
	// expires := time.Unix(1558131350, 0)

	sep := '?'
	if strings.ContainsRune(urlPrefix, '?') {
		sep = '&'
	}

	toSign := fmt.Sprintf(
		"URLPrefix=%s&Expires=%d&KeyName=%s",
		base64.RawURLEncoding.EncodeToString([]byte(urlPrefix)),
		expires.Unix(),
		keyName,
	)
	sig := ed25519.Sign(privateKey, []byte(toSign))

	fmt.Fprintf(
		w,
		"%s%c%s&Signature=%s",
		urlPrefix,
		sep,
		toSign,
		base64.RawURLEncoding.EncodeToString(sig),
	)

	return nil
}

Python

Media CDN に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。 詳細については、ローカル開発環境の認証を設定するをご覧ください。

import base64
import datetime

import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519


from six.moves import urllib

def sign_url_prefix(
    url: str,
    url_prefix: str,
    key_name: str,
    base64_key: str,
    expiration_time: datetime.datetime,
) -> str:
    """Gets the Signed URL string for the specified URL prefix and configuration.

    Args:
        url: URL of request.
        url_prefix: URL prefix to sign as a string.
        key_name: name of the signing key as a string.
        base64_key: signing key as a base64 encoded string.
        expiration_time: expiration time as a UTC datetime object.

    Returns:
        Returns the Signed URL appended with the query parameters based on the
        specified URL prefix and configuration.
    """
    stripped_url = url.strip()
    parsed_url = urllib.parse.urlsplit(stripped_url)
    query_params = urllib.parse.parse_qs(parsed_url.query, keep_blank_values=True)
    encoded_url_prefix = base64.urlsafe_b64encode(
        url_prefix.strip().encode("utf-8")
    ).decode("utf-8")
    epoch = datetime.datetime.utcfromtimestamp(0)
    expiration_timestamp = int((expiration_time - epoch).total_seconds())
    decoded_key = base64.urlsafe_b64decode(base64_key)

    policy_pattern = (
        "URLPrefix={encoded_url_prefix}&Expires={expires}&KeyName={key_name}"
    )
    policy = policy_pattern.format(
        encoded_url_prefix=encoded_url_prefix,
        expires=expiration_timestamp,
        key_name=key_name,
    )

    digest = ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key).sign(
        policy.encode("utf-8")
    )
    signature = base64.urlsafe_b64encode(digest).decode("utf-8")
    signed_url = "{url}{separator}{policy}&Signature={signature}".format(
        url=stripped_url,
        separator="&" if query_params else "?",
        policy=policy,
        signature=signature,
    )
    return signed_url

次のコードサンプルは、署名付き URL Cookie をプログラムで作成する方法を示しています。

署名付きパス コンポーネントを作成する

次のコードサンプルは、署名付きパス コンポーネントをプログラムで作成する方法を示しています。

Python

Media CDN に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。 詳細については、ローカル開発環境の認証を設定するをご覧ください。

import base64
import datetime
import hashlib
import hmac

import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519


def base64_encoder(value: bytes) -> str:
    """
    Returns a base64-encoded string compatible with Media CDN.

    Media CDN uses URL-safe base64 encoding and strips off the padding at the
    end.
    """
    encoded_bytes = base64.urlsafe_b64encode(value)
    encoded_str = encoded_bytes.decode("utf-8")
    return encoded_str.rstrip("=")


def sign_path_component(
    url_prefix: str,
    filename: str,
    key_name: str,
    base64_key: str,
    expiration_time: datetime.datetime,
) -> str:
    """Gets the Signed URL string for the specified URL prefix and configuration.

    Args:
        url_prefix: URL Prefix to sign as a string.
        filename: The filename of the sample request
        key_name: The name of the signing key as a string.
        base64_key: The signing key as a base64 encoded string.
        expiration_time: Expiration time as a UTC datetime object with timezone.

    Returns:
        Returns the Signed URL appended with the query parameters based on the
        specified URL prefix and configuration.
    """

    expiration_duration = expiration_time.astimezone(
        tz=datetime.timezone.utc
    ) - datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc)
    decoded_key = base64.urlsafe_b64decode(base64_key)

    policy_pattern = "{url_prefix}edge-cache-token=Expires={expires}&KeyName={key_name}"
    policy = policy_pattern.format(
        url_prefix=url_prefix,
        expires=int(expiration_duration.total_seconds()),
        key_name=key_name,
    )

    digest = ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key).sign(
        policy.encode("utf-8")
    )
    signature = base64_encoder(digest)

    signed_url = "{policy}&Signature={signature}/{filename}".format(
        policy=policy, signature=signature, filename=filename
    )

    return signed_url

必須の署名欄

すべての署名に次のフィールドが必要です。

  • Expires
  • KeyName
  • Signature

クエリ パラメータが存在する場合は、URL の最後のパラメータとしてグループ化する必要があります。特に指定しない限り、パラメータ名とその値では大文字と小文字が区別されます。

各パラメータについて、次の表に説明します。

フィールド名 署名パラメータ 署名付きの値
Expires Unix エポックからの整数の経過秒数(1970-01-01T00:00:00Z) Expires=EXPIRATION_TIME。この日時を過ぎると、署名は無効になります。
KeyName このリクエストの署名に使用される EdgeCacheKeyset の名前。KeyName は、キーセット自体の個々のキーではなく、キーセット全体を指します。 KeyName=EDGE_CACHE_KEYSET
Signature 署名の base64 エンコード バージョン。 該当なし

オプションの署名欄

クエリ パラメータが存在する場合は、URL の最後のパラメータとしてグループ化する必要があります。特に指定しない限り、パラメータ名とその値では大文字と小文字が区別されます。

次の表に、各パラメータの名前と、オプションの署名パラメータの詳細を示します。

フィールド名 署名パラメータ 署名付きの値
HeaderName

リクエストに存在する必要がある名前付きリクエスト ヘッダー フィールド名。

ヘッダー フィールド名では大文字と小文字が区別されるため、署名時には小文字にする必要があります。Media CDN は、署名を検証する前にヘッダーを小文字に変換します。

HeaderName=HEADER_NAME
HeaderValue リクエストに存在する必要がある名前付きリクエスト ヘッダー フィールド値。これは通常、ユーザー ID などの不透明な識別子です。HeaderValue が指定され、HeaderName が指定されていないリクエストは拒否されます。 HeaderValue=HEADER_VALUE
IPRanges

この URL がウェブセーフ base64 形式で有効な、CIDR 形式の IPv4 アドレスと IPv6 アドレスのリスト(最大 5 つ)。たとえば、IP 範囲「192.6.13.13/32,193.5.64.135/32」を指定するには、IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy を指定します。

クライアントが WAN 移行の危険にさらされている場合や、アプリケーション フロントエンドへのネットワーク パスが配信パスと異なる場合は、IPRanges を署名に含めることは役に立ちません。 署名付きリクエストに含まれていない IP アドレスに接続すると、Media CDN は HTTP 403 コードを持つクライアントを拒否します。

以下のような場合、Media CDN は HTTP 403 コードを持つクライアントを拒否します。

  • デュアルスタック(IPv4、IPv6)環境
  • 接続の移行(Wi-Fi からモバイル、モバイルから Wi-Fi)
  • 携帯通信会社ゲートウェイ NAT(CGNAT または CGN)を使用するモバイル ネットワーク
  • マルチパス TCP(MPTCP)

これらの要因はすべて、動画再生セッション中に特定のクライアントが確定的でない IP アドレスを持つ原因となります。アクセスの発行後にクライアント IP アドレスが変更され、クライアントが動画セグメントを再生バッファにダウンロードしようとすると、Media CDN から HTTP 403 を受信します。

IPRanges=BASE_64_IP_RANGES
URLPrefix アクセス権を付与する base64(URL セーフ)URL 接頭辞。URLPrefix を指定すると、接頭辞に署名して、プレーヤーまたはマニフェスト生成内の複数の URL に同じクエリ パラメータを追加できます。 署名付き Cookie 形式を使用する場合、URLPrefix が必要です。 URLPrefix=BASE_64_URL_PREFIX