HTTPS, Tokens, and DRM are 3 core technologies that secure video streaming against unauthorized access, interception, and piracy. HTTPS encrypts data in transit between servers and clients, preventing interception or tampering. It manifests, segments, and license requests transmit over TLS, with mobile SDKs like ExoPlayer and AVFoundation blocking non-HTTPS connections by default.

Tokens control access by validating viewer permissions before delivering content. JWTs or signed URLs embed expiry times, user IDs, or geo-restrictions, which CDNs or backend services enforce. Tokens are validated per request to reject unauthorized access with HTTP 401/403 responses.

DRM provides persistent content protection using encryption and license enforcement. Systems like Widevine, FairPlay, and PlayReady encrypt video and bind decryption keys to authorized devices or sessions. License servers verify device attestation before issuing keys to prevent unauthorized redistribution. DRM works alongside HTTPS and tokens for end-to-end security.

Transport Security and Delivery Encryption

HTTPS

HTTPS encrypts video streams during transit, preventing man-in-the-middle attacks. Without HTTPS, attackers intercept cleartext video segments, manifest files, or license requests. Modern mobile SDKs, such as ExoPlayer and AVFoundation, reject HTTP requests by default. CDNs like Akamai and Cloudflare enforce TLS 1.2+ for video delivery. Misconfigured servers allowing HTTP fallback expose streams to eavesdropping.

Tokens

Tokens authenticate requests for video segments and manifests. A JSON Web Token (JWT) with a sub claim restricts access to specific users. The following Python snippet validates a JWT before granting access:

code
import jwt
code
from cryptography.hazmat.primitives import serialization
code

code
public_key = serialization.load_pem_public_key(open('public.pem').read())
code
try:
code
payload = jwt.decode(token, public_key, algorithms=["RS256"])
code
if payload["exp"] < datetime.utcnow().timestamp():
code
raise ValueError("Token expired")
code
except jwt.InvalidTokenError:
code
deny_access()

Explanation:

  • Imports the jwt module to handle JSON Web Token encoding and decoding.
  • Imports serialization from cryptography.hazmat.primitives to load the public key.
  • Uses serialization.load_pem_public_key to read and parse the public key from a PEM file named public.pem.

DRM

DRM systems like Widevine, FairPlay, and PlayReady encrypt video content end-to-end. The client requests a license key after authenticating, and the key exchange occurs over HTTPS. Widevine’s license server checks device attestation before issuing decryption keys. Unencrypted CMAF or DASH segments fail playback on DRM-enabled clients.

Access Control and Request Validation

HTTPS

HTTPS alone does not restrict access; any client with the URL retrieves the stream. Certificate pinning prevents impersonation attacks but complicates CDN switching. Android’s Network Security Configuration enforces HTTPS for all media requests:

code
<network-security-config>
code
<domain-config cleartextTrafficPermitted="false">
code
<domain includeSubdomains="true">video.example.com</domain>
code
</domain-config>
code
</network-security-config>

Explanation:

  • Starts with <network-security-config> to define security policies for network traffic in Android apps.
  • <domain-config cleartextTrafficPermitted="false"> blocks all unencrypted HTTP traffic to the specified domain.
  • <domain includeSubdomains="true">video.example.com</domain> applies the security policy to video.example.com and all its subdomains.

Tokens

Tokens embed access policies, such as geo-restrictions or IP whitelisting. A CDN validates the token before serving content. CloudFront signed URLs append a signature and expiry:

code
https://d123.cloudfront.net/video.mp4?Expires=1625097600&Signature=...&Key-Pair-Id=...

DRM

DRM licenses bind to a specific device or session. FairPlay’s SKD protocol requires a certificate chain and content key context (CKC). Clients without a valid license receive HTTP 403.

Persistent Protection and Rights Management

HTTPS

HTTPS encryption terminates at the CDN or playback device. Persistent protection requires additional measures, such as encrypted storage for source files. AWS S3 buckets storing video assets should enforce x-amz-server-side-encryption headers.

Tokens

Short-lived tokens limit exposure. Refresh tokens reissue access tokens without user interaction. The following JWT claim set restricts stream access to 10 minutes:

code
{
code
"exp": Math.floor(Date.now() / 1000) + 600,
code
"user_id": "u123",
code
"content_id": "v456"
code
}

Explanation:

  • Starts with a JSON object representing the payload of a JWT (JSON Web Token).
  • "exp": Math.floor(Date.now() / 1000) + 600 sets the token’s expiration time to 10 minutes (600 seconds) from the current time.
  • "user_id": "u123" identifies the user associated with the token.

DRM

DRM persists encryption after delivery. Widevine’s L1 security level stores keys in hardware-backed keystores. Offline playback licenses enforce expiration policies.

Policy Enforcement and Playback Failures

HTTPS

Clients block mixed content. iOS AVPlayer logs NSURLErrorServerCertificateUntrusted for invalid certificates. Android’s MediaDrm throws MediaDrm.MediaDrmStateException for insecure connections.

Tokens

Expired tokens return HTTP 401. The CDN must not cache 401 responses. AWS Lambda@Edge validates tokens before forwarding requests to the origin:

code
exports.handler = async (event) => {
code
const request = event.Records[0].cf.request;
code
const token = request.querystring.split('token=')[1];
code
if (!validateToken(token)) {
code
return { status: '401', body: 'Unauthorized' };
code
}
code
return request;
code
};

Explanation:

  • Exports an async function named handler to run as a Lambda@Edge function.
  • Retrieves the HTTP request from the first CloudFront event record using event.Records[0].cf.request.
  • Extracts the token from the query string by splitting on 'token=' and taking the value that follows.
  • Checks if the token is valid using validateToken(token) and returns a 401 Unauthorized response if it fails.

DRM

License rotation invalidates compromised keys. PlayReady’s KeyRotation attribute in the manifest triggers key renewal. Clients without updated keys stall playback.

Edge Caching and Token Expiry Management

HTTPS

CDNs cache encrypted segments but bypass the cache for token validation. CloudFront’s Cache-Control: private directive prevents edge caching of personalized streams.

Tokens

Token expiry must align with cache TTLs. A 5-minute token with a 10-minute cache TTL allows unauthorized access. Fastly’s VCL checks token expiry before serving cached content:

code
sub vcl_recv {
code
if (req.url ~ "token=") {
code
declare local var.expiry INTEGER;
code
set var.expiry = std.atoi(regsub(req.url, ".*exp=([0-9]+).*", "\1"));
code
if (var.expiry < now) {
code
return (synth(401, "Unauthorized"));
code
}
code
}
code
}

Explanation:

  • Starts with sub vcl_recv, which defines a Varnish VCL subroutine that processes incoming client requests.
  • Checks if the request URL contains the string "token=" to identify tokenized URLs.
  • Declares a local integer variable var.expiry, to store the token’s expiration timestamp.
  • Uses regsub and std.atoi to extract and convert the exp value from the URL into an integer.

DRM

Edge servers do not cache licenses. Widevine’s license server checks X-Forwarded-For to enforce regional policies.

Ingest and Preprocessing Security

HTTPS

Upload endpoints must use HTTPS with client certificates. AWS Elemental MediaLive requires HTTPS input and IAM role authentication.

Tokens

Pre-signed URLs grant temporary upload access:

code
aws s3 presign s3://upload-bucket/video.mp4 --expires-in 3600

DRM

Ingested content is encrypted before storage. AWS Elemental MediaPackage applies AES-128 encryption during packaging.

Transcoding and Packaging Security

HTTPS

Transcoding services fetch source files over HTTPS. Misconfigured HTTP endpoints expose raw video to interception.

Tokens

FFmpeg accesses token-protected sources with HTTP headers:

code
ffmpeg -headers "Authorization: Bearer ${TOKEN}" -i https://source/video.mp4 ...

DRM

Packaging tools like Shaka Packager inject DRM metadata:

code
packager \
code
input=video.mp4,stream=video,output=encrypted_video.mp4 \
code
--enable_widevine_encryption \
code
--key_server_url "https://license.example.com"

Explanation:

  • Starts with packager, a command-line tool used to encrypt and package media content for streaming.
  • input=video.mp4,stream=video,output=encrypted_video.mp4 specifies the source file, its stream type, and the output file name after encryption.
  • --enable_widevine_encryption activates encryption using the Widevine DRM system.

Storage and Access Control for Video Assets

HTTPS

S3 buckets should disable public access. Pre-signed URLs grant temporary read access:

code
s3.generate_presigned_url('get_object', Params={'Bucket': 'videos', 'Key': 'stream.mpd'}, ExpiresIn=3600)

Experiment:

  • Calls s3.generate_presigned_url to create a temporary URL for accessing a private S3 object.
  • Specifies 'get_object' as the operation, allowing read access to the object.
  • Uses Params={'Bucket': 'videos', 'Key': 'stream.mpd'} to identify the S3 bucket and the specific media file.

Tokens

Storage systems like Azure Blob support token-based access:

code
{
code
"Version": "2020-02-10",
code
"Statement": [{ "Action": "read", "Resource": "blob:video/*", "Condition": { "IpAddress": { "aws:SourceIp": "192.0.2.0/24" } } }]
code
}

Explanation:

  • "Version": "2020-02-10" specifies the policy language version used for evaluation.
  • "Action": "read" allows read access to the specified resources.
  • "Resource": "blob:video/*" targets all video blobs under the blob:video namespace.

DRM

Encrypted assets store key IDs in the manifest. Clients request keys using the KID and content ID.

Playback Enforcement and Client-Side Policies

HTTPS

Clients enforce HTTPS via platform APIs. Android’s StrictMode blocks cleartext traffic:

code
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectCleartextNetwork().penaltyLog().build());

Explanation:

  • Calls StrictMode.setVmPolicy to apply a custom virtual machine policy for the Android app.
  • Uses detectCleartextNetwork() to flag any attempt to use unencrypted HTTP connections.
  • Adds penaltyLog() to log violations to Logcat instead of crashing the app.

Tokens

Players append tokens to segment requests. ExoPlayer’s DefaultHttpDataSourceFactory injects headers:

code
DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory()
code
.setDefaultRequestProperties(Map.of("Authorization", "Bearer " + token));

Explanation:

  • Creates a DataSource.Factory instance using DefaultHttpDataSource.Factory() for loading media over HTTP.
  • Calls setDefaultRequestProperties to attach default headers to all HTTP requests made by the player.
  • Passes a map containing the Authorization header with a Bearer token, enabling authenticated media access.

DRM

Clients attach device certificates to license requests. iOS FairPlay requires AVAssetResourceLoaderDelegate to handle key requests:

code
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
code
guard let url = loadingRequest.request.url else { return false }
code
if url.scheme == "skd" {
code
handleFairPlayRequest(loadingRequest)
code
return true
code
}
code
return false
code
}

Explanation:

  • Implements the resourceLoader(_:shouldWaitForLoadingOfRequestedResource:) delegate method for intercepting media loading requests in AVFoundation.
  • Uses loadingRequest.request.url to extract the requested URL from the loading request.
  • Checks if the URL scheme is "skd" to indicate a FairPlay Streaming license request.
  • Calls handleFairPlayRequest(loadingRequest) to handle the license retrieval and response.