如何使用 CloudFront 从 AWS S3 安全地播放 .m3u8 流文件?

Posted

技术标签:

【中文标题】如何使用 CloudFront 从 AWS S3 安全地播放 .m3u8 流文件?【英文标题】:How to securely play .m3u8 streaming file from AWS S3 using CloudFront? 【发布时间】:2020-09-15 05:41:43 【问题描述】:

我正在使用 CloudFront 签名 URL 来显示来自 S3 的图像和视频以确保安全。

它适用于图像和其他视频,除了 .m3u8 文件。

我使用了 AWS php SDK,这是我的代码。

<?php
    // Instantiate the CloudFront client with your AWS credentials
    $cloudFrontClient    =  new CloudFrontClient(array(
        'region'        => env('AWS_DEFAULT_REGION'),
        'version'       => 'latest',
        'http'          => [ 'verify' => false ],
        'credentials'   => array(
            'key'       => env('AWS_ACCESS_KEY_ID'),
            'secret'    => env('AWS_SECRET_ACCESS_KEY'),
    )));
    
    // Create a signed URL for the resource
    $resourceKey      =  'https://abcdefg.cloudfront.net/test/file_1000k.m3u8';
        $expires          =  time() + 3600;
        $signedUrl        =  $cloudFrontClient->getSignedUrl([
            'url'         => $resourceKey,
            'expires'     => $expires,
            'private_key' => public_path().'/pk-ABCD123.pem',
            'key_pair_id' => 'ABCD123ABCD123ABCD123'
        ]);
?>
    <video id='hls-example' class="video-js vjs-default-skin"   controls>
        <source src="<?php echo $signedUrl; ?>" type="application/x-mpegURL">
        Your browser does not support the video tag.
    </video>
    
    <script src="https://vjs.zencdn.net/7.2.3/video.js"></script>
    <script src="<?php echo asset('public/assets/js/videojs-contrib-hls.min.js'); ?>"></script>
    <script>
        var player = videojs('hls-example');
        player.play();
    </script>

如果我没记错的话,它不会播放,因为我们还需要对 .m3u8 文件中的分段文件 (.ts) 进行签名。

我们如何动态改变它?

有什么方法可以安全播放.m3u8文件,让用户无法使用直接链接访问下载文件?

【问题讨论】:

【参考方案1】:

CloudFront 签名的 URL 在只有一个文件时效果很好,但就像您发现当您有多个资源时它是一个问题。

因此,推荐的方法是使用signed CloudFront cookies。

通过这样做,您只需签名一次即可允许来自特定 CloudFront 分配的所有资源,并且无需在每次页面加载时都为签名过程而烦恼。

【讨论】:

啊,你知道如何实现它吗? 它与签名 URL 的过程类似,您使用 CLI 或 SDK。这个页面有更多关于实现细节的信息:docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/…【参考方案2】:

这是一篇很好的 AWS 文章,可帮助您在 (1) cookie 和 (2) 签名 URL 之间做出选择:-

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html

我最初研究了 cookie 方法,但选择单独签署 HLS 清单文件中的每个 URL。我使用 ffmpeg 将 MP4 文件转换为 HLS(例如 Mp4 to HLS using ffmpeg),HLS 清单将类似于:-

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:17
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:16.683333,
my-video0.ts
#EXTINF:8.341667,
my-video1.ts
#EXTINF:8.341667,
my-video2.ts

...

#EXT-X-ENDLIST

您将单独签署每个片段,例如

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:17
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:16.683333,
https://cqtgd3b9n5c6qp.cloudfront.net/my-video0.ts?Expires=1609499278&Key-Pair-Id=AIRPEGWQPKAIQ7O3SPLI&Signature=KUvRsV-OpJ014ZQ0dLZF....
#EXTINF:8.341667,
https://cqtgd3b9n5c6qp.cloudfront.net/my-video1.ts?Expires=1609499278&Key-Pair-Id=AIRPEGWQPKAIQ7O3SPLI&Signature=KlVQsz5TVzhEQ8LKs1ZW....
#EXTINF:8.341667,
https://cqtgd3b9n5c6qp.cloudfront.net/my-video2.ts?Expires=1609499278&Key-Pair-Id=AIRPEGWQPKAIQ7O3SPLI&Signature=VR1MBzq~pVsBfOzjZa~M....

...

#EXT-X-ENDLIST

简单的搜索/替换会动态生成这个文件。

对每个 URL 进行签名将需要一些处理,因此我在返回 HLS 清单时将 Expires 标头 (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires) 添加到 HTTP 响应中。这样可以确保浏览器中的后续调用使用缓存副本,从而大大提高性能。

注意 - 重要的是 HTTP 响应中的过期时间(略)小于签名 URL 中的过期时间。

我发现单独签署每个 URL 更安全,您无需担心域等问题,但实施起来可能稍微复杂(代码方面)。

【讨论】:

以上是关于如何使用 CloudFront 从 AWS S3 安全地播放 .m3u8 流文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C# HttpClient 或 AWS SDK 通过 CloudFront 将视频上传到 S3

如何在 AWS S3 网站 CloudFront 中设置别名重定向?

允许用户从 AWS s3 或 Cloudfront 批量下载文件

AWS CloudFront 如何遵循 S3 存储桶重定向规则?

没有 S3 存储桶的 AWS Cloudfront CORS 标头

AWS Elastic Beanstalk / S3 / CloudFront Cache-Control 标头