Generar firmas

En esta guía, se explica cómo crear una firma y los campos obligatorios y opcionales para las firmas.

Para crear una firma, debes redactar una string para firmar, a la que nos referimos como valor firmado en esta guía. El valor firmado incluye parámetros que describen el contenido que proteges, la fecha de vencimiento del valor firmado, etcétera.

Usas el valor firmado mientras creas una string de firma. Para crear una string de firma, debes componer los parámetros de la firma, como una firma asimétrica de clave asimétrica Ed25519 del valor firmado.

Media CDN usa la firma compuesta final para ayudar a proteger el contenido.

Formatos de firma compatibles

Media CDN admite los siguientes formatos de solicitud firmados.

Formato Comportamiento Ejemplo
Parámetros de consulta (URL exacta)

URL exacta, para otorgar acceso a una URL específica.

Exacto:

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

Parámetros de consulta (prefijo de URL) Especificar un URLPrefix te permite firmar un prefijo y adjuntar los mismos parámetros de consulta a varias URL dentro de tu jugador o generación de manifiesto.

Qué firmar:

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

Reemplaza PREFIX por el prefijo al que se debe otorgar acceso, incluidos el esquema, el host y la ruta de acceso parcial.

Componente de ruta

Prefijo: Permite el acceso a cualquier URL con un prefijo antes del componente "/edge-cache-token=[...]".

Esto permite que las URL de manifiesto relativas hereden de forma automática el componente de URL firmado cuando se recuperan subrecursos.

https://media.example.com/video/edge-cache-token=Expires=EXPIRATION
&KeyName=KEY_NAME
&Signature=SIGNATURE/manifest_12382131.m3u8
Cookie firmada Prefijo: La cookie permite el acceso a cualquier URL con el prefijo especificado en el valor URLPrefix firmado.

Cookie de almacenamiento en caché perimetral:

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

Crea una firma

  1. Crea un valor firmado mediante la concatenación de una string que contenga los campos de firma obligatorios y los campos de firma opcionales deseados.

    Si se especifica, URLPrefix debe ir primero, seguido de Expires, KeyName y, luego, cualquier parámetro opcional.

    Separa cada campo y cualquier parámetro con lo siguiente:

    • Para las cookies, usa un carácter : de dos puntos.
    • Para los parámetros de consulta y los componentes de ruta de acceso, usa un carácter et &.
  2. Firma el valor firmado con una firma Ed25519.

  3. Agrega un separador de campo (: o &) seguido de Signature= y la firma Ed25519 al final de la string.

Crea una URL firmada

En las siguientes muestras de código, se muestra cómo crear de manera programática una URL firmada.

Go

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Crea un prefijo de URL firmada

En las siguientes muestras de código, se muestra cómo crear de manera programática un prefijo de URL firmado.

Go

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

En las siguientes muestras de código, se muestra cómo crear de manera programática una cookie de URL firmada.

Crea un componente de ruta de acceso firmado

En las siguientes muestras de código, se muestra cómo crear de manera programática un componente de ruta firmada.

Python

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Campos de firma obligatorios

Los siguientes campos son obligatorios para cada firma:

  • Expires
  • KeyName
  • Signature

Si los parámetros de consulta están presentes, deben agruparse como los últimos parámetros en la URL. A menos que se especifique lo contrario, en los nombres de los parámetros y en sus valores, se distingue entre mayúsculas y minúsculas.

En la siguiente tabla, se explica cada parámetro:

Nombre del campo Parámetros de firma Valor con firma
Expires Número entero de segundos que transcurrieron desde la época Unix (1970-01-01T00:00:00Z) Expires=EXPIRATION_TIME, después de lo cual la firma ya no es válida.
KeyName El nombre de EdgeCacheKeyset que se usa para firmar esta solicitud. KeyName hace referencia a todo el conjunto de claves, no a claves individuales dentro del conjunto de claves. KeyName=EDGE_CACHE_KEYSET
Signature Una versión codificada en Base64 de la firma. No aplicable

Campos de firma opcionales

Si los parámetros de consulta están presentes, deben agruparse como los últimos parámetros en la URL. A menos que se especifique lo contrario, en los nombres de los parámetros y en sus valores, se distingue entre mayúsculas y minúsculas.

En la siguiente tabla, se explica el nombre y cada detalle de cada parámetro para los parámetros de firma opcionales:

Nombre del campo Parámetros de firma Valor con firma
HeaderName

Un nombre de campo de encabezado de solicitud que debe estar presente en la solicitud.

Debe estar en minúscula cuando se firma porque los nombres de campo de encabezado distinguen entre mayúsculas y minúsculas. Media CDN reduce el encabezado antes de validar la firma.

HeaderName=HEADER_NAME
HeaderValue Un valor de campo de encabezado de solicitud con nombre que debe estar presente en la solicitud. Por lo general, es un ID de usuario o algún otro identificador opaco. Las solicitudes con HeaderValue, pero sin HeaderName, se rechazan. HeaderValue=HEADER_VALUE
IPRanges

Una lista de hasta cinco direcciones IPv4 e IPv6 en formato CIDR para las que esta URL es válida en formato base64 seguro para la Web. Por ejemplo, para especificar los rangos de IP “192.6.13.13/32,193.5.64.135/32”, debes especificar IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy.

Es posible que los IPRanges no sean útiles para incluir en las firmas cuando los clientes están en riesgo de migraciones de WAN o casos en los que la ruta de red al frontend de tu aplicación es diferente de la ruta de entrega. Media CDN rechaza a los clientes con un código HTTP 403 cuando se conectan con una dirección IP que no forma parte de la solicitud firmada.

Los siguientes son casos que pueden provocar que Media CDN rechace a los clientes con un código HTTP 403:

  • Entornos de doble pila (IPv4, IPv6)
  • Migración de conexión (Wi-Fi a móvil y de móvil a Wi-Fi)
  • Redes móviles que usan NAT de puerta de enlace del proveedor (CGNAT o CGN)
  • TCP de varias rutas (MPTCP)

Todos estos factores pueden contribuir a que un cliente determinado tenga una dirección IP no determinista durante una sesión de reproducción de video. Si la dirección IP del cliente cambia después de que emites el acceso y el cliente intenta descargar un segmento de video en su búfer de reproducción, recibe un HTTP 403 de Media CDN.

IPRanges=BASE_64_IP_RANGES
URLPrefix Prefijo de URL base64 (seguro para URL) al que se otorga acceso. Especificar un URLPrefix te permite firmar un prefijo y adjuntar los mismos parámetros de consulta a varias URL dentro de tu generación de manifiesto o jugador. El URLPrefix es obligatorio cuando se usa el formato de cookie firmada. URLPrefix=BASE_64_URL_PREFIX