Media CDN 支持使用多种签名方式,防止信息内容未授权分发。令牌(Token)认证可以将客户端请求信息都构造在一个特殊格式的令牌中,并将令牌附加在请求的 URL 参数中发出,从而对信息内容进行保护。令牌认证方式丰富了 Media CDN 现有的 URL鉴权方式。Media CDN 现在可以支持使用 ED25519 非对称签名,或者使用基于 HMAC 的对称签名令牌方式。
概览
Media CDN 支持双令牌认证,即使用一个短效令牌,一个长效令牌对内容进行保护。本文将模拟一个视频播放场景,介绍如何使用双令牌方式对内容进行保护。
假设视频资源中包括以下内容

Media CDN 使用以下流程对内容进行双令牌认证
1. 客户端使用短效令牌访问主播放清单 master.m3u8
2. Media CDN 认证成功后将长效令牌添加到主播放清单并返回(如果认证失败则返回 403)
3. 客户端收到带有长效令牌的主播放清单 master.m3u8 后,开始对其中的带有长效令牌的媒体播放列表 index.m3u8 进行请求
4. Media CDN 收到并认证成功后将长效令牌添加到 index.m3u8 中媒体内容分段 index.ts
5. 客户端收到后,请求带有长效令牌的 index.ts 文件,播放内容。
创建令牌
Media CDN 使用 Google Cloud Secret Manager 保存 HMAC 使用共享密钥。在本地新建一个 shared.secret 文件,输入共享密钥后保存。为确正确上传密钥,在本地使用 gsutil 计算文件 shared.secret 的 CRC32,并记录。
gsutil hash -c -h "shared.secret" |
在 Secret Manager 中建立密钥,并确保上传后 CRC32 校验相同
gcloud secrets create yinghli-shared-secret --data-file=shared.secret
|
Secret Manager 对 Media CDN 进行授权访问,注意替换 $project_number
gcloud secrets add-iam-policy-binding \\ projects/$project_number/secrets/yinghli-shared-secret \\ --member="serviceAccount:service-$project_number@gcp-sa-mediaedgefill.iam.gserviceaccount.com" \\ --role="roles/secretmanager.secretAccessor"
|
Media CDN 中使用共享密钥创建短效令牌 yinghli-short-keyset
gcloud edge-cache keysets create yinghli-short-keyset \\ --validation-shared-key="secret_version=projects/$project_number/secrets/yinghli-shared-secret/versions/1"
|
Media CDN 中使用 Google Cloud 托管方式创建长效令牌 yinghli-long-keyset
gcloud edge-cache keysets create yinghli-long-keyset \\ --public-key='id=google-managed-key,managed=true'
|
创建源文件
在 GCS 中创建一个私有测试桶 yinghli-dual-token-bucket,并针对 Media CDN 进行访问授权。替换对应的 $project_id 和 $project_number
gsutil mb -p $project_id gs://yinghli-dual-token-bucket
gsutil iam ch \\ serviceAccount:service-$project_number@gcp-sa-mediaedgefill.iam.gserviceaccount.com:objectViewer \\ gs://yinghli-dual-token-bucket
|
在根目录/ 下,准备一个测试使用的主播放清单 master.m3u8,该文件将使用短效令牌鉴权
#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2" low/index.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=1920x1080,CODECS="avc1.42e00a,mp4a.40.2" high/index.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5" audio/index.m3u8
|
在 /high 目录下,准备媒体播放清单 index.m3u8 文件,该文件使用长效令牌鉴权
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:13 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:12.416667, index0.ts #EXTINF:7.716667, index1.ts #EXT-X-ENDLIST
|
生成一个测试 index0.ts 并上传到 /high 目录下
echo "example data" > index0.ts |
创建 Media CDN 源
gcloud edge-cache origins create yinghli-dual-token-origin \\ --origin-address="gs://yinghli-dual-token-bucket"
|
Media CDN 配置
Media CDN 基本配置,包括证书设定,缓存策略制定和路由设计等请参见上手指南。本文使用域名 dual.yinghli.cn进行部署,并在证书和DNS上做了对应设定。本章节将重点介绍双令牌的配置和测试方式。
针对主播放清单 master.m3u8,设定最高优先等级的路由策略,并指定对应短效令牌 keyset 参数。短效令牌位置通过 hdnts 确定。其中令牌算法除了 SHA256 外,还支持 ED25519 和 HMAC_SHA1。本文长效令牌添加方式为 cookieless,除此之外还支持 GENERATE_COOKIE。copiedParameters 支持的其他参数请参见。
pathMatchers: - name: routes routeRules: - priority: 1 # 最先匹配短效令牌 matchRules: - pathTemplateMatch: /*.m3u8 # 匹配主播放清单 origin: yinghli-dual-token-origin routeAction: cdnPolicy: signedRequestMode: REQUIRE_TOKENS # 使用令牌认证 signedRequestKeyset: yinghli-short-keyset # 使用短效令牌keyset signedTokenOptions: tokenQueryParameter: hdnts # 请求中包含的短效令牌参数位置 allowedSignatureAlgorithms: # 设定令牌算法 - HMAC_SHA_256 addSignatures: actions: - GENERATE_TOKEN_HLS_COOKIELESS # 生成长效令牌并插入媒体播放清单 keyset: yinghli-long-keyset # 使用长效令牌keyset tokenTtl: 1200s # 设定过期时间 tokenQueryParameter: hdntl # 长效令牌位置参数 copiedParameters: - URLPrefix # 从短效令牌中复制参数 |
针对其余媒体播放清单 index.m3u8 和内容文件 index.ts,设定长效令牌策略,长效令牌位置通过 hdntl 确定
- priority: 2 matchRules: - pathTemplateMatch: /**.m3u8 # 所有非根目录.m3u8 origin: yinghli-dual-token-origin routeAction: cdnPolicy: signedRequestMode: REQUIRE_TOKENS # 使用令牌认证 signedRequestKeyset: yinghli-long-keyset # 使用长效令牌keyset signedTokenOptions: tokenQueryParameter: hdntl # 长效令牌参数位置 addSignatures: actions: - PROPAGATE_TOKEN_HLS_COOKIELESS # 生成长效令牌并插入媒体文件中 tokenQueryParameter: hdntl # 长效令牌位置参数 - priority: 3 matchRules: - pathTemplateMatch: /**.ts # 匹配所有媒体分段文件 origin: yinghli-dual-token-origin routeAction: cdnPolicy: signedRequestMode: REQUIRE_TOKENS # 使用令牌认证 signedRequestKeyset: yinghli-long-keyset # 使用长效令牌keyset signedTokenOptions: tokenQueryParameter: hdntl # 长效令牌位置 |
测试结果
客户端生成 HMAC 短效令牌访问请求。短效令牌生成代码请参见这里。以下为测试调用结果
if __name__ == "__main__": urlprefix = 'https://dual.yinghli.cn/' encry_type = 'sha256' expiresTime = datetime.datetime.strptime("2023-03-27T23:00:00Z", "%Y-%m-%dT%H:%M:%S%z") with open("shared.secret", "rb") as fp: key = fp.read() key_str = base64.urlsafe_b64encode(key) sign = sign_token(key_str,encry_type,None,expiresTime,urlprefix,None,None,None,None,None,None) print (sign)
|
本示例中仅使用最简单 urlprefix 进行鉴权,指定过期时间,从 shared.secret 中读取共享密钥,并进行 base64 编码后输入 sign _token 函数,最后得到 HMAC 结果 URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Expires=1679958000~hmac=xxxx
将该结果与访问 URL 合并生成使用短效令牌校验的请求(令牌位置通过参数 hdnts 确定),发送给 Media CDN 并接收返回的带有长效令牌的 signed_master.m3u8
curl -svq "https://dual.yinghli.cn/master.m3u8?hdnts=URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Expires=1679958000~hmac=xxx" > signed_master.m3u8 | tee signed_master.m3u8 |
通过打开 signed_master.m3u8 发现,其中的链接均为使用长效令牌生成的 URL
#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2" low/index.m3u8?hdntl=Expires=1679882846~_GO=Generated~URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Signature=xxx #EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2" high/index.m3u8?hdntl=Expires=1679882846~_GO=Generated~URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Signature=xxx #EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5" audio/index.m3u8?hdntl=Expires=1679882846~_GO=Generated~URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Signature=xxx |
我们通过访问长效令牌签算的 high/index.m3u8 链接 URL 可以收到带有长效令牌的 signed_index.m3u8
curl -svq "https://dual.yinghli.cn/$(grep high/index.m3u8 signed_master.m3u8)" \\ > signed_index.m3u8 | tee signed_index.m3u8 |
通过打开 signed_index.m3u8 发现,其中所包含的 ts 链接均使用长效令牌生成的 URL
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:13 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:12.416667, index0.ts?hdntl=Expires=1679896557~_GO=Generated~URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Signature=xxx #EXTINF:7.716667, index1.ts?hdntl=Expires=1679896557~_GO=Generated~URLPrefix=aHR0cHM6Ly9kdWFsLnlpbmdobGkuY24v~Signature=xxx #EXT-X-ENDLIST |
通过 curl 读取 index0.ts 文件,获取到原始文字 example data
curl -sv "https://dual.yinghli.cn/high/$(grep index0.ts signed_index.m3u8)" |
综上,本文介绍了 Media CDN 双令牌认证的过成,并通过模拟验证了整个过程。其他功能,请案件产品文档。