יצירת חתימות

במדריך הזה מוסבר איך ליצור חתימה, ומהם שדות החובה והשדות האופציונליים בחתימות.

כדי ליצור חתימה, צריך ליצור מחרוזת לחתימה, שאנחנו קוראים לה ערך חתום במדריך הזה. הערך החתום כולל פרמטרים שמתארים את התוכן שאתם מגנים עליו, את תוקף הערך החתום וכו'.

משתמשים בערך החתום בזמן יצירת מחרוזת חתימה. יוצרים מחרוזת חתימה על ידי הרכבת הפרמטרים של החתימה, כמו חתימת 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 בקידומת של הגישה שרוצים להעניק, כולל הסכימה, המארח והנתיב החלקי.

רכיב נתיב

קידומת: מאפשרת גישה לכל כתובת URL עם קידומת לפני הרכיב "/edge-cache-token=[...]".

כך כתובות URL יחסיות של קובץ מניפסט יכולות לקבל באופן אוטומטי את רכיב כתובת ה-URL החתומה כשמאחזרים משאבי משנה.

https://media.example.com/video/edge-cache-token=Expires=EXPIRATION
&KeyName=KEY_NAME
&Signature=SIGNATURE/manifest_12382131.m3u8
קובץ Cookie חתום קידומת: קובץ ה-Cookie מאפשר גישה לכל כתובת URL עם הקידומת שצוינה בערך URLPrefix החתום.

Edge-Cache-Cookie:

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

יצירת חתימה

  1. יוצרים ערך חתום על ידי שרשור מחרוזת שמכילה את שדות החתימה הנדרשים ואת שדות החתימה האופציונליים הרצויים.

    אם מציינים את הפרמטר URLPrefix, הוא חייב להופיע ראשון, ואחריו הפרמטרים Expires, KeyName וכל הפרמטרים האופציונליים.

    מפרידים בין כל שדה ובין כל פרמטר באמצעות התווים הבאים:

    • לגבי קובצי Cookie, משתמשים בתו נקודתיים :.
    • לפרמטרים של שאילתות ולרכיבי נתיב, משתמשים בתו אמפרסנד &.
  2. חתימה על הערך החתום באמצעות חתימת Ed25519.

  3. מוסיפים מפריד שדות (: או &) ואחריו Signature= ואת חתימת Ed25519 לסוף המחרוזת.

יצירת כתובת URL חתומה

בדוגמאות הקוד הבאות אפשר לראות איך ליצור כתובת URL חתומה באופן פרוגרמטי.

Go

כדי לבצע אימות ב-Media CDN, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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

בדוגמאות הקוד הבאות אפשר לראות איך ליצור קובץ Cookie של כתובת URL חתומה באופן פרוגרמטי.

יצירת רכיב נתיב חתום

בדוגמאות הקוד הבאות אפשר לראות איך ליצור רכיב חתום של נתיב באופן פרוגרמטי.

Python

כדי לבצע אימות ב-Media CDN, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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 epoch) (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 ערך של שדה כותרת בקשה עם שם שחייב להיות נוכח בבקשה. בדרך כלל זה מזהה משתמש או מזהה אטום אחר. בקשות עם HeaderValue אבל בלי HeaderName נדחות. HeaderValue=HEADER_VALUE
IPRanges

רשימה של עד חמש כתובות IPv4 ו-IPv6 בפורמט CIDR, שכתובת ה-URL הזו תקפה לגביהן בפורמט base64 בטוח לשימוש באינטרנט. לדוגמה, כדי לציין את טווחי כתובות ה-IP ‏192.6.13.13/32,193.5.64.135/32, מציינים את IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy.

יכול להיות שטווח כתובות ה-IP לא יעזור לכם לכלול בחתימות כשלקוחות נמצאים בסיכון להעברות WAN או במקרים שבהם נתיב הרשת לחלק הקדמי של האפליקציה שונה מנתיב המסירה. ‫Media CDN דוחה לקוחות עם קוד HTTP 403 כשהם מתחברים עם כתובת IP שלא כלולה בבקשה החתומה.

אלה מקרים שבהם יכול להיות ש-Media CDN ידחה לקוחות עם קוד HTTP 403:

  • סביבות עם תמיכה כפולה (IPv4, ‏ IPv6)
  • העברת חיבור (מ-Wi-Fi לרשת סלולרית, ומחיבור לרשת סלולרית ל-Wi-Fi)
  • רשתות סלולריות שמשתמשות ב-NAT של שער הספק (CGNAT או CGN)
  • ‫Multi-path TCP (MPTCP)

כל הגורמים האלה יכולים לגרום לכך שללקוח מסוים תהיה כתובת IP לא דטרמיניסטית במהלך הפעלת סרטון. אם כתובת ה-IP של הלקוח משתנה אחרי שניתנה גישה, והלקוח מנסה להוריד קטע וידאו למאגר הזמני להפעלה, הוא מקבל קוד שגיאה HTTP 403 מ-Media CDN.

IPRanges=BASE_64_IP_RANGES
URLPrefix קידומת כתובת ה-URL בקידוד base64 (בטוח לשימוש בכתובת URL) של כתובת ה-URL שאליה רוצים להעניק גישה. ציון של URLPrefix מאפשר לכם לחתום על תחילית ולצרף את אותם פרמטרים של שאילתה לכמה כתובות URL בתוך הנגן או יצירת המניפסט. הפרמטר URLPrefix נדרש כשמשתמשים בפורמט של קובץ Cookie חתום. URLPrefix=BASE_64_URL_PREFIX