서명 생성

이 가이드에서는 서명을 만들고 서명에 대해 필수 및 선택적 필드를 만드는 방법을 설명합니다.

서명을 만들려면 이 가이드에서 서명 값이라고 부르는 서명할 문자열을 구성합니다. 서명 값에는 보호 대상 콘텐츠, 서명 값의 만료 시간 등을 기술하는 매개변수가 포함됩니다.

서명 문자열을 만드는 동안 서명 값을 사용합니다. 서명된 키의 비대칭 키 Ed25519 서명과 같이 서명에 대한 매개변수를 작성하여 서명 문자열을 만듭니다.

Media CDN은 콘텐츠 보호를 돕기 위해 최종 구성 서명을 사용합니다.

지원되는 서명 형식

Media CDN은 다음과 같은 서명된 요청 형식을 지원합니다.

형식 동작
쿼리 매개변수(정확한 URL)

특정 URL에 대한 액세스 권한을 부여하는 정확한 URL입니다.

정확:

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
서명된 쿠키 프리픽스: 이 쿠키는 서명된 URLPrefix 값에 지정된 프리픽스로 시작하는 모든 URL에 대한 액세스를 허용합니다.

Edge-Cache-Cookie:

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

서명 만들기

  1. 필수 서명 필드 및 원하는 선택적 서명 필드가 포함된 문자열을 연결하여 서명 값을 만듭니다.

    지정된 경우 URLPrefix가 먼저 오고 그 뒤에 Expires, KeyName 및 선택적 매개변수가 와야 합니다.

    각 필드와 매개변수를 다음과 같이 분리합니다.

    • 쿠키의 경우 콜론 : 문자를 사용합니다.
    • 쿼리 매개변수 및 경로 구성요소의 경우 앰퍼샌드 & 문자를 사용합니다.
  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 쿠키를 프로그래매틱 방식으로 만드는 방법을 보여줍니다.

서명된 경로 구성요소 만들기

다음 코드 샘플은 서명된 경로 구성요소를 프로그래매틱 방식으로 만드는 방법을 보여줍니다.

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 유닉스 시간(1970-01-01T00:00:00Z)을 기준으로 경과한 정수 초입니다. Expires=EXPIRATION_TIME, 이후에는 서명이 더 이상 유효하지 않습니다.
KeyName 이 요청을 서명하는 데 사용된 EdgeCacheKeyset의 이름입니다. KeyName은 키 세트 자체 내에 있는 개별 키가 아닌 전체 키 세트를 나타냅니다. KeyName=EDGE_CACHE_KEYSET
Signature base-64로 인코딩된 서명 버전입니다. 해당 사항 없음

선택적 서명 필드

쿼리 매개변수가 제공되었으면 URL에서 마지막 매개변수로 하나로 그룹화해야 합니다. 달리 지정되지 않은 한 매개변수 이름과 값은 대소문자를 구분합니다.

다음 표에서는 각 매개변수의 이름과 선택적 서명 매개변수의 세부정보를 설명합니다.

필드 이름 서명 매개변수 서명 값
HeaderName

요청에 제공되어야 하는 이름 지정된 요청 헤더 필드 이름입니다.

헤더 필드 이름은 대소문자를 구분하므로 서명 시 소문자여야 합니다. Media CDN은 서명을 검증하기 전에 헤더를 소문자로 변환합니다.

HeaderName=HEADER_NAME
HeaderValue 요청에 제공되어야 하는 이름 지정된 요청 헤더 필드 값입니다. 이는 일반적으로 사용자 ID 또는 기타 불투명한 식별자입니다. HeaderValue가 있고 HeaderName이 없는 요청은 거부됩니다. HeaderValue=HEADER_VALUE
IPRanges

이 URL이 웹 안전 base64 형식으로 유효한 CIDR 형식에서 최대 5개의 IPv4 및 IPv6 주소 목록입니다. 예를 들어 IP 범위를 "192.6.13.13/32,193.5.64.135/32"로 지정하려면 IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy를 지정합니다.

클라이언트에 WAN 마이그레이션 위험이 있거나 애플리케이션 프런트엔드에 대한 네트워크 경로가 전송 경로와 다른 경우에는 IPRanges를 서명에 포함하는 것이 유용하지 않을 수 있습니다. Media CDN은 서명된 요청에 속하지 않는 IP 주소로 연결될 때 HTTP 403 코드로 클라이언트를 거부합니다.

다음은 Media CDN이 HTTP 403 코드로 클라이언트를 거부할 수 있는 경우입니다.

  • 이중 스택(IPv4, IPv6) 환경
  • 연결 마이그레이션(WiFi-이동통신 및 이동통신-WiFi)
  • 이동통신사 게이트웨이 NAT(CGNAT 또는 CGN)를 사용하는 모바일 네트워크
  • 다중 경로 TCP(MPTCP)

이러한 모든 요소는 지정된 클라이언트가 동영상 재생 세션 중 비결정적 IP 주소를 갖도록 하는 데 기여할 수 있습니다. 접근이 허용된 후 클라이언트 IP 주소가 변경되고 클라이언트가 동영상 세그먼트를 재생 버퍼에 다운로드하려고 시도하면 Media CDN에서 HTTP 403이 수신됩니다.

IPRanges=BASE_64_IP_RANGES
URLPrefix 액세스 권한을 부여할 base64(URL 안전) URL 프리픽스입니다. URLPrefix를 지정하면 프리픽스를 서명하고 플레이어 또는 매니페스트 생성 내에서 여러 URL에 동일한 쿼리 매개변수를 추가할 수 있습니다. 서명된 쿠키 형식을 사용하는 경우 URLPrefix가 필요합니다. URLPrefix=BASE_64_URL_PREFIX