通过 CloudFront 进行私有 HTTP 实时流式传输

Posted

技术标签:

【中文标题】通过 CloudFront 进行私有 HTTP 实时流式传输【英文标题】:Private HTTP Live Streaming via CloudFront 【发布时间】:2013-10-17 21:36:24 【问题描述】:

我正在开发一个 iOS 应用,它允许下载和 HTTP 直播 私人视频。视频存储在 Amazon S3 存储桶中(作为 mp4 并分段为 m3u8/ts 文件)。 CloudFront 也已打开并连接到存储桶。

由于内容是私有的,我需要在通过 CloudFront 连接时对 URL 进行签名。为了对 URL 进行签名,必须使用私钥,因此如果不将私钥存储在包中,就无法在 ios 应用程序中生成签名 URL。那是个坏主意!

所以我决定编写一个简单的 Ruby 服务器,它执行 URL 签名并重定向到生成的签名 CloudFront URL,如下所示:


http://signing.server.local/videos/1.mp4https://acbdefg123456.cloudfront.net/videos/1.mp4??Expires=XXX&Signature=XXX&Key-Pair-Id=XXX

http://signing.server.local/videos/1.m3u8https://acbdefg123456.cloudfront.net/videos/1.m3u8??Expires=XXX&Signature=XXX&Key-Pair-Id=XXX


对于视频下载,它运行良好,因为只有一个请求。但是,当我希望内容流式传输并为 MPMoviePlayerController 提供签名服务器的 URL 时,只有第一个请求由服务器签名并重定向到 CloudFront。对于下一个请求,MPMoviePlayerController 将第一个签名的 CloudFront URL 作为基础,并尝试直接连接而不抛出签名服务器。

m3u8 文件中的路径是相对的

有什么建议可以在不需要通过签名服务器发送所有内容的情况下实现此功能?

【问题讨论】:

【参考方案1】:

使用 S3/CloudFront 或任何其他存储/CDN 进行私有 HLS 的正确方法是使用 HLS 加密。请参阅Apple documentation about this topic。

除了存储播放列表和分段视频文件的存储空间之外,您还必须集成一个安全的 HTTPS 服务器来存储***播放列表和密钥。这些密钥是在分段期间使用 Apple HLS 工具生成的。

这是它的工作原理:

    MPMoviePlayerController 获取指向安全 HTTPS 服务器上***播放列表 (.m3u8) 的 URL。 在此文件中,有指向存储在 S3/CloudFront 中的变体播放列表 (prog_index.m3u8) 的链接,这些链接指向视频文件 (.ts)。 此外,变体播放列表包含指向键的链接,这些键是读取视频文件所必需的。这些密钥也存储在安全的 HTTPS 服务器上。

见下图:

取自演示文稿Mobile Movies with HTTP LIve Streaming (CocoaConf DC, Jun '12)

当然,有可能使基础架构更安全,请参阅链接的 Apple 文档。

我还创建了一个用于分段的 Ruby 脚本,以使用给定的基本 URL 生成输出,这使事情变得更加简单。

【讨论】:

这个答案出现在我关于使用云端保护 HLS 视频的搜索顶部。我认为它有点过时了,所以我想通过指出安全 cookie 是限制对云端 HLS 访问的主要 AWS 示例用例之一来修改答案:docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/… 正如 Tatyree 所指出的,建议 Safari 等浏览器使用安全 cookie。我为另一个问题写了一个解决方案,可以在该帖子上以评论/答案***.com/a/64988224/1207732 的形式找到它。希望对您有所帮助。【参考方案2】:

卢卡斯·库巴内克有正确的答案。但是,您可以通过将***播放列表放在“私有”存储桶中,然后将所有其他播放列表和 .ts 文件放在公共存储桶中来获得签名 URL 的效果。这与对所有内容使用签名 URL 一样安全,因为任何想要下载和保存内容的人仍然可以下载和保存内容,但不能仅仅共享他们提供的 URL。他们当然可以打开***播放列表,然后共享他们选择的单个流,或者自己托管***播放列表,但这至少是一个小的安全级别,可能足以满足您的内容。此外,如果您对每个片段都签名,您会遇到内容超过您的时间限制的问题,或者用户只是暂停视频直到片段链接过期。

【讨论】:

我很想了解一下这是如何完成的。例如,.m3u8 播放列表文件是通过指向其他存储桶中的文件(如 http://d17hw8d9njib15.cloudfront.net/somefile/hls400k.m3u8http://d17hw8d9njib15.cloudfront.net/somefile/hls400k.m3u8)创建的吗?【参考方案3】:

我认为您需要一些方法来避免为每个视频块向不同服务器发出两个请求。

可能的解决方案:您能否每隔几分钟更改一次 Cloudfront 私钥?如果是,那么只需根据需要进行身份验证(双向握手)并将当前私钥发送给应用程序。如果它过期了,或者由于它没有在预期的时间过期而导致任何错误,只需重新验证并获取新的私钥。

可能的解决方案:当您想播放视频 X 时与身份验证服务器对话,并为该视频的每个部分获取签名 URL,或者更好:包含签名 URL 的 m3u8 文件。然后,直接播放那些...

可能的解决方案:通过本地代理运行所有内容(在 iOS 设备上的环回接口上)。然后根据需要修改请求 URL,或者使它们重定向。

【讨论】:

以上是关于通过 CloudFront 进行私有 HTTP 实时流式传输的主要内容,如果未能解决你的问题,请参考以下文章

如何使用预设策略加密 Amazon CloudFront 签名以进行私有内容访问

尝试使用 cloudfront 和 privateKey 访问存储在 S3(静态 Web 托管)中的私有内容时获得 HTTP/1.1 403 Forbidden

Cloudfront 私有内容 + 签名 URL 架构

如何使用 RTMP 和 Flowplayer 从 Cloudfront 运行私有内容视频

在 S3 和 cloudfront 上使用 rails carrierwave 私有文件

使用 Ruby 为 CloudFront 创建签名 URL