Generar firmas

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

Para crear una firma, debes componer una cadena que se va a firmar, a la que llamamos valor firmado en esta guía. El valor firmado incluye parámetros que describen el contenido que estás protegiendo, el tiempo de vencimiento del valor firmado, etc.

El valor firmado se usa al crear una cadena de firma. Para crear una cadena de firma, debes componer los parámetros de la firma, como una firma Ed25519 de clave asimétrica del valor firmado.

Media CDN usa la firma compuesta final para proteger tu contenido.

Formatos de firma admitidos

Media CDN admite los siguientes formatos de solicitud firmada.

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

URL exacta para conceder acceso a una URL específica.

Exacta:

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

Parámetros de consulta (prefijo de URL) Si especifica un URLPrefix, puede firmar un prefijo y añadir los mismos parámetros de consulta a varias URLs en su reproductor o en la generación de manifiestos.

Qué firmar:

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

Sustituye PREFIX por el prefijo al que quieras conceder acceso, incluido el esquema, el host y la ruta parcial.

Componente de ruta

Prefijo: permite el acceso a cualquier URL con un prefijo anterior al componente "/edge-cache-token=[...]".

De esta forma, las URLs de manifiesto relativas pueden heredar automáticamente el componente de URL firmado al obtener 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 acceder a cualquier URL con el prefijo especificado en el valor URLPrefix firmado.

Edge-Cache-Cookie:

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

Crear una firma

  1. Crea un valor firmado concatenando una cadena que contenga los campos de firma obligatorios y los campos de firma opcionales que quieras.

    Si se especifica, URLPrefix debe ir en primer lugar, seguido de Expires, KeyName y, a continuación, los parámetros opcionales.

    Separa cada campo y los parámetros con lo siguiente:

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

  3. Añade un separador de campos (: o &) seguido de Signature= y la firma Ed25519 al final de la cadena.

Crear una URL firmada

En los siguientes ejemplos de código se muestra cómo crear una URL firmada mediante programación.

Go

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en 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. Para obtener más información, consulta el artículo Configurar la autenticación en 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

Crear un prefijo de URL firmada

En los siguientes ejemplos de código se muestra cómo crear de forma programática un prefijo de URL firmado.

Go

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en 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. Para obtener más información, consulta el artículo Configurar la autenticación en 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 los siguientes ejemplos de código se muestra cómo crear una cookie de URL firmada mediante programación.

Crear un componente de ruta firmado

En los siguientes ejemplos de código se muestra cómo crear un componente de ruta firmada mediante programación.

Python

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en 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 en todas las firmas:

  • Expires
  • KeyName
  • Signature

Si hay parámetros de consulta, deben agruparse como los últimos parámetros de la URL. A menos que se indique lo contrario, en los nombres de los parámetros y 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 firmado
Expires Número entero de segundos transcurridos desde el inicio del registro de tiempo de Unix (1970-01-01T00:00:00Z). Expires=EXPIRATION_TIME, después de la cual la firma deja de ser válida.
KeyName El nombre del EdgeCacheKeyset usado para firmar esta solicitud. KeyName hace referencia a todo el conjunto de claves, no a las claves individuales que contiene. KeyName=EDGE_CACHE_KEYSET
Signature Versión de la firma codificada en base64. No aplicable

Campos de firma opcionales

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

En la siguiente tabla se explica el nombre y los detalles de cada parámetro de firma opcional:

Nombre del campo Parámetros de firma Valor firmado
HeaderName

Nombre de un campo de encabezado de solicitud con nombre que debe estar presente en la solicitud.

Debe estar en minúsculas cuando se firme, ya que los nombres de los campos de encabezado distinguen entre mayúsculas y minúsculas. Media CDN convierte el encabezado a minúsculas antes de validar la firma.

HeaderName=HEADER_NAME
HeaderValue Valor de un campo de encabezado de solicitud con nombre que debe estar presente en la solicitud. Normalmente, se trata de un ID de usuario u otro identificador opaco. Las solicitudes con HeaderValue pero sin HeaderName se rechazan. HeaderValue=HEADER_VALUE
IPRanges

Lista de hasta cinco direcciones IPv4 e IPv6 en formato CIDR para las que esta URL es válida en formato base64 seguro para web. Por ejemplo, para especificar los intervalos de IP "192.6.13.13/32,193.5.64.135/32", debe especificar IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy.

Puede que no sea útil incluir IPRanges en las firmas cuando los clientes corran el riesgo de sufrir migraciones de WAN o en los casos en los que la ruta de red al frontend de tu aplicación sea 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.

A continuación, se indican algunos casos que pueden provocar que Media CDN rechace a los clientes con un código HTTP 403:

  • Entornos de doble pila (IPv4 e IPv6)
  • Migración de la conexión (de Wi-Fi a datos móviles y de datos móviles a Wi-Fi)
  • Redes móviles que usan NAT de pasarela de operador (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 vídeo. Si la dirección IP del cliente cambia después de que hayas concedido acceso y el cliente intenta descargar un segmento de vídeo en su búfer de reproducción, recibirá un HTTP 403 de Media CDN.

IPRanges=BASE_64_IP_RANGES
URLPrefix Prefijo de URL base64 (seguro para URLs) para conceder acceso. Si especifica un URLPrefix, puede firmar un prefijo y añadir los mismos parámetros de consulta a varias URLs de su reproductor o de su generación de manifiestos. El campo URLPrefix es obligatorio cuando se usa el formato de cookie firmada. URLPrefix=BASE_64_URL_PREFIX