解释阿里云视频点播内容安全机制的文章
1. 概述
如何保障视频内容的安全,不被盗链、非法下载和传播,是困扰众多企业已久的问题,特别是独播剧、在线教育、财经金融、行业培训等在线版权视频领域尤为迫切,处理不好会造成极为严重的经济损失,甚至法律风险。
阿里云视频点播提供了完善的内容安全保护机制,可以满足不同业务场景的安全需求。
2. 访问限制
访问限制是在云端配置视频资源的访问策略,达到基本的保护目的,主要手段有:
- Referer、IP和UA(User-Agent)的黑白名单
- 一定周期内,URL的访问次数限制、独立IP数限制
2.1 Referer黑白名单
- 基于 HTTP 协议支持的 Referer机制,通过 Referer跟踪来源,对来源进行识别和判断,用户可配置访问的 Referer 黑、白名单(二者互斥)来限制视频资源被访问的情况。
- 支持黑名单和白名单两种模式,访客对资源发起请求后,请求到达CDN 节点,节点会根据用户预设的防盗 链黑名单或白名单进行过滤,符合规则可顺利请求到视频数据;若不符合,请求会被拒绝,并返回403响应 码。
- 配置后会自动添加泛域名支持,例如填写a.com,最终配置生效的是*.a.com,所有子级域名都会生效。
- 由于移动端一般拿不到Referer,当前默认支持空Referer访问,可选择关闭。
示例
设置点播域名 vod-test1.cn-shanghai.aliyuncs.com 的Referer白名单为 aliyun.com,且不允许空Referer访问,请求 数据:
curl -i 'http://vod-test1.cn-shanghai.aliyuncs.com/sv/5101d1f8-1643f9ab241/5101d1f8-1643f9ab241.mp4'
返回
当请求带上允许的referer后即正常返回:
curl -i 'http://vod-test1.cn-shanghai.aliyuncs.com/sv/5101d1f8-1643f9ab241/5101d1f8-1643f9ab241.mp4' \
-H 'Referer: http://www.aliyun.com'
2.2 UA黑白名单
UA(User-Agent)是一个特殊字符串头,帮助服务端识别用户使用的操作系统及版本、CPU类型、浏览器及版本、 浏览器渲染引擎&语言和插件等。可通过UA黑白名单来限制特定浏览器或终端的访问。
如PC端IE9浏览器:
UserAgent:Mozilla/5.0(compatible;MSIE9.0;WindowsNT6.1;Trident/5.0;
可模拟HTTP请求验证:
curl -i 'http://vod-test1.cn-shanghai.aliyuncs.com/sv/5101d1f8-1643f9ab241/5101d1f8-1643f9ab241.mp4' \
-H 'User-Agent: iPhone OS;MI 5'
2.3 IP黑白名单
视频点播支持配置IP黑名单或白名单,拒绝或只允许特定IP的访问。
- 支持IP列表添加,并支持添加IP网段,例如127.0.0.1/24。
网段127.0.0.1/24,24表示采用子网掩码中的前24位为有效位,即用32-24=8bit来表示主机号,该子网可以容纳2^8 - 2 = 254 台主机,故可表示IP网段范围:127.0.0.1~127.0.0.255。
- 可选择优先使用 remote_addr 或 X-Forwarded-For(XFF) 作为请求端IP,或者同时匹配。
2.4 访问次数和独立IP数限制
点播服务可限制媒体资源在一定时间周期内(如1天)的最大访问次数和最大独立IP数,核心原理是所有请求先到中心化的访问计数服务进行验证,判断是否超过预设的阈值,若超过则拒绝服务,返回HTTP 403。
- 该限制为URL(包括文件地址和签名信息)维度而非文件维度,但可配置忽略URL中的部分参数;限制的阈 值到域名粒度,可单独设置。
- 访问计数服务是多区域部署的中心化服务,一个URL只能被调度到其中一个区域,以保证中心化计数。
- CDN边缘节点收到请求后会访问中心化计数服务进行计数和验证。
2.5 小结
- 访问限制的使用门槛很低,只需简单配置即可使用,能起到一定的保护作用,特别是Web端。
- Referer和UA都是基于HTTP Header,容易被伪造,安全性低。
- IP黑白名单机制和访问数限制,无法实现内容分发给大量C端用户,不适合广泛的内容消费场景,且后者在 阈值范围内也可能被非法访问。
3. 播放中心鉴权
播放地址若固定不变会带来持久的非法扩散传播,且无法有效遏制,视频点播提供的URL鉴权可通过生成动态的加密URL(包含权限验证、过期时效等信息)来区分合法请求,以达到保护视频资源的目的。
- 开启URL鉴权后,点播的播放器SDK、获取播放地址的API/SDK都会自动生成带时效的播放URL;如需要自己生成鉴权的动态URL,则可使用下述 鉴权 法。
- 开启URL鉴权后,所有媒体资源,包括视频、音频、封面、截图等地址都会进行鉴权。
- 鉴权Key的设置是以域名为粒度,且存于服务端以确保安全;支持主、备Key平滑切换,若更换主Key,可使用备Key生成播放地址,以做为更换的桥接,实现交替更新。
鉴权方法
鉴权URL构成
http://DomainName/Filename?auth_key=timestamp-rand-uid-md5hash
鉴权URL由播放文件地址+验证串构成,验证串是根据鉴权key+过期时间通过md5算法计算得出,且具有时效性, 默认为3600秒(可后台配置)的有效时间,可在生成播放地址或获取地址时设置过期时间;若地址过期则访问时 CDN会返回HTTP 403。
动态地址示例
http://vod.example.com/video/aliyun-sample.mp4?auth_key=1500523200-0-0-80cd3862d699b7118eed99103f2a3a4f
示例中的auth_key参数值前缀1500523200(时间为2017-07-20 12:00:00),表示该地址会在2017-07-20 13:00:00过期。
更多信息可参考 阿里云视频点播-URL鉴权。
4. 业务方二次鉴权
播放中心鉴权使用了阿里云的默认鉴权中心,但由于没有客户业务请求信息的输入,对盗链等非法请求的判断还比较单一,使用二次鉴权会更加精准。
- 二次鉴权是指点播CDN将用户的请求透传到客户的鉴权中心,由客户自己判定该请求是否合法,CDN根据 客户的判断结果执行相应动作:允许或拒绝访问。
- 二次鉴权需要客户自己开发和部署鉴权中心,该鉴权中心的域名如果同时在 CDN上面加速,可以按照一定 规则缓存客户的鉴权结果,以减轻客户鉴权中心的压力。点播CDN会默将把用户请求的 headers 和 request_uri 透传到客户自定义的鉴权中心,并根据鉴权中心返回的结果执行相应的动作。过程如下图:
如业务方可将其用户的登录Cookie或UUID等信息隐藏于播放请求中,进而透传到自己的鉴权中心以判定是否为合法用户。
5. 视频加密
防盗链安全机制能有效保障用户的合法访问,但对于付费观看视频的场景,用户只需通过一次付费行为拿到视频合 法的防盗链播放URL,将视频下载到本地,进而实现二次分发。因此,防盗链方案对于视频版权保护是远远不够的。视频文件一旦泄露,会给付费观看模式造成十分严重的经济损失。
阿里云视频加密是对视频数据加密,即使下载到本地,视频本身也是被加密的,无法恶意二次分发,可有效防止视频泄露和盗链问题。
5.1 阿里云视频加密
阿里云视频加密采用私有的加密算法和安全传输机制,提供云端一体的视频安全方案,核心部分包括 “加密转码” 和 “解密播放”。
核心优势:
- 每个媒体文件拥有独立的加密钥匙,能有效避免采用单一密钥时,一个密钥的泄露引起大范围的安全问题。
- 提供信封加密机制“密文Key+明文Key”,仅密文Key入库,明文Key不落存储,所有过程只在内存中,用完 即销毁。
- 提供安全的播放器内核SDK,涵盖iOS/Android/Flash多平台,自动对加密内容进行解密播放;H5播放器不支持加密视频的播放。
- 播放器和云端使用私有加密协议进行密文传输,不传输明文Key,有效防止密钥被窃取。
- 提供安全下载,缓存到本地的视频会再次加密,在确保无网离线播放前提下,防止视频被拷贝窃取。
注意:阿里云视频加密仅支持输出HLS格式,且只能使用阿里云播放器。 更多信息参考 阿里云-视频加密
5.2 HLS标准加密
HLS标准加密支持 HTTP Live Streaming 中规定的通用加密方案,使用AES-128对视频内容本身进行加密,同时能 支持所有的HLS播放器,用户可选择使用自研或开源的播放器。相比私有加密方案,灵活性更好,但使用门槛更 高、安全性更低:
- 用户需搭建密钥管理服务,提供密钥生成(用于转码时对视频内容进行加密)和解密服务(用于播放时获取 解密密钥),也可基于 阿里云KMS 进行封装。
- 用户需提供令牌颁发服务,用于验证播放端的身份,避免解密密钥被非法获取,此处为关键点,处理不好会千里之堤溃于蚁穴。
- 播放器和云端传输明文Key,容易被窃取。
更多信息参考 阿里云-HLS标准加密
5.3 小结
视频加密方案各有优劣,一般来说,越是标准、通用,灵活性越高,但安全性越低,选择哪种方案取决于自己的业务场景,有所取舍:
安全等级:阿里云视频加密 > HLS标准加密
阿里云视频加密安全性明显高于HLS标准加密。
易用性:阿里云视频加密 > HLS标准加密
阿里云视频加密提供云端一体解决方案,只需简单配置并接入阿里云播放器即可无缝集成加密能力;HLS标准加密需自建密钥管理和令牌颁发服务。
通用性:HLS标准加密 > 阿里云视频加密
HLS标准加密可适配所有M3U8播放场景;阿里云视频加密仅支持阿里云播放器 (Android/iOS/Flash)。
使用费用:阿里云视频加密 = HLS标准加密
阿里云视频加密和HLS标准加密都可免费使用。
- iOS/Android/Flash使用阿里云视频加密或HLS标准加密会有很好的安全性;但由于H5端为明文,要保证更高的安全性首选商业DRM(Chrome等浏览器的原生支持)。
了解与开通视频点播服务
了解视频安全解决方案
活动推荐
12月20日杭州站【云栖TechDay-音视频技术实战沙龙】,多位视频云专家现场解读短视频、直播、视频AI、视频加速技术实践,赢取阿里云公仔及代金券,点击了解活动详情及免费报名:https://yq.aliyun.com/event/678
上一篇: 企业远程智能视频服务场景中的 OWT
下一篇: B 站直播如何观看分区
推荐阅读
-
解释阿里云视频点播内容安全机制的文章
-
iCloud 切换区域,中国区保留 appStore(更新)--自 2018 年 2 月 28 日起,中国区 iCloud 由云上贵州管理 苹果公司发布的公告 https://support.apple.com/zh-cn/HT208352 关键词 关键部分 受影响的 iCloud 账户:国家或地区设置为 "中国 "的 Apple ID。 iCloud 包含的服务照片、邮件、通讯录、日历、提醒事项、备忘、书签、钱包、钥匙串、云备份、云驱动器、应用程序数据 新条款和条件: 同意仅出于本协议允许的目的并在中国法律允许的范围内使用服务。 云桂洲在提供服务时应使用合理的技能并尽职尽责,但在适用法律允许的最大范围内,我们不保证或担保您通过本服务存储或访问的任何内容不会意外损坏、崩溃、丢失或根据本协议的条款被删除,如果发生此类损坏、崩溃、丢失或删除,我们不承担任何责任。您应自行负责维护您的信息和数据的适当备份。 Apple 和云上贵州有权访问您存储在服务中的所有数据,包括有权根据适用法律相互之间共享、交换和披露所有用户数据(包括内容)。 本协议的解释、效力和履行应适用*法律。对于因本协议引起的或与本协议有关的任何争议,云桂洲和您同意提交中国国际经济贸易仲裁委员会(CIETAC)根据提交仲裁时有效的法律在北京进行具有约束力的仲裁。 由云桂洲管理,用户选择: 停用; ID 到地区; 受 iCloud(由云桂洲运营)条款和条件约束 首先,我想说说我对数据安全的看法。 当我在朋友圈发布通知时,有些朋友回复说国外的操作并没有多安全,或者国外的安全只是相对于国外而言的等等。首先,我非常感谢这些朋友,这让我反思什么是数据安全。以下观点均属个人观点: 国外的月亮一定比国内圆? 这是一个根深蒂固的问题,只要有人说国外的东西比国内好,就会有人嘲笑崇洋媚外。我觉得我们在某些方面应该向国外学习,比如搜索引擎和版权问题。打开百度搜索 "数据安全",第一行肯定是广告。打开谷歌搜索 "数据安全",第一条就是 "数据安全_百度百科" .....各种版权问题大家都明白,支持正版,但不仅客户一心想找免费破解,就连作者也往往没有保护自己劳动成果或产品的想法。但从另一个层面来说,国内的发展和安全,甩国外几条街。没有说哪里好,哪里不好,辩证地去学习更好。 国外也有别有用心的数据泄露,谈何安全? 从加密解密的角度看,自古以来就没有绝对安全的加密,只有相对安全的做法。苹果的棱镜门、微软的 cpu 漏洞,各种参差不齐的被破解案例 ....是的,这的确是一个很好的论据,但凡事都不能只看一面,当年苹果面对FBI破解手机的要求,几经论证,苹果还是拒绝破解。这点拿到国内,只要上面的文件传达下去,还有企业敢说不吗?还敢说不吗? 关于这次iCloud数据迁移个人看法? 把数据迁移到贵州的云端,相当于把手机的所有数据都存储在贵州的云端服务器上。也许访问数据的速度会快很多,但我会把我的iCloud区放到美国,因为我不想数据存在云上贵州后经常接到莫名其妙的电话或短信,更不想因为乱用国外服务器而被请去喝茶。iCloud一个ID,即从中国账号转到美国区,主要用于数据存在美国服务器上。appStore一个ID,除了注册一个中国ID外,专门用来下载应用用,因为国外ID不支持酷狗和网易云等应用。麻烦的是,用了新的 appStore ID 后,当前的应用还得重新下载安装,因为旧的应用 ID 与新的应用 ID 不兼容,安装不了。最后,iCloud迁移后,国内用户使用美国服务器,估计要 "扶墙 "了。 专业步骤: 首先,进行appleID设置,这是前提条件,否则无法选择转移区域! 取消 appleID 的双重认证 取消家庭共享选项 二、窗口下载并安装 icloud 3.0 版
-
F#探险之旅(二):函数式编程(上)-函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP)、命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程。回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前。第二种FP语言是Lisp,产生于1958,早于Cobol一年。Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟,至今已是最流行的编程范式。有道是“*代有语言出,各领风骚数十年”。 尽管强大的FP语言(SML,Ocaml,Haskell及Clean等)和类FP语言(APL和Lisp是现实世界中最成功的两个)在1950年代就不断发展,FP仍停留在学院派的“象牙塔”里;而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天,FP的潜力终被认识——它是用来解决更复杂的问题的(当然更简单的问题也不在话下)。 纯粹的FP将程序看作是接受参数并返回值的函数的集合,它不允许有副作用(side effect,即改变了状态),使用递归而不是循环进行迭代。FP中的函数很像数学中的函数,它们都不改变程序的状态。举个简单的例子,一旦将一个值赋给一个标识符,它就不会改变了,函数不改变参数的值,返回值是全新的值。 FP的数学基础使得它很是优雅,FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题,它的优势之一就是融合了多种编程范式,允许开发人员按照需要采用最好的范式。 关于FP的更多内容建议阅读一下这篇文章:Why Functional Programming Matters(中文版)。F#中的函数式编程 从现在开始,我将对F#中FP相关的主要语言结构逐一进行介绍。标识符(Identifier) 在F#中,我们通过标识符给值(value)取名字,这样就可以在后面的程序中引用它。通过关键字let定义标识符,如: let x = 42 这看起来像命令式编程语言中的赋值语句,两者有着关键的不同。在纯粹的FP中,一旦值赋给了标识符就不能改变了,这也是把它称为标识符而非变量(variable)的原因。另外,在某些条件下,我们可以重定义标识符;在F#的命令式编程范式下,在某些条件下标识符的值是可以修改的。 标识符也可用于引用函数,在F#中函数本质上也是值。也就是说,F#中没有真正的函数名和参数名的概念,它们都是标识符。定义函数的方式与定义值是类似的,只是会有额外的标识符表示参数: let add x y = x + y 这里共有三个标识符,add表示函数名,x和y表示它的参数。关键字和保留字关键字是指语言中一些标记,它们被编译器保留作特殊之用。在F#中,不能用作标识符或类型的名称(后面会讨论“定义类型”)。它们是: abstract and as asr assert begin class default delegate do donedowncast downto elif else end exception extern false finally forfun function if in inherit inline interface internal land lazy letlor lsr lxor match member mod module mutable namespace new nullof open or override private public rec return sig static structthen to true try type upcast use val void when while with yield 保留字是指当前还不是关键字,但被F#保留做将来之用。可以用它们来定义标识符或类型名称,但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性,最好不要使用。它们是: atomic break checked component const constraint constructor continue eager event external fixed functor global include method mixinobject parallel process protected pure sealed trait virtual volatile 文字值(Literals) 文字值表示常数值,在构建计算代码块时很有用,F#提供了丰富的文字值集。与C#类似,这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等,在此不再赘述,详细信息请查看F#手册。 与C#一样,F#中的字符串常量表示也有两种方式。一是常规字符串(regular string),其中可包含转义字符;二是逐字字符串(verbatim string),其中的(")被看作是常规的字符,而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示: let message = "Hello World"r"n!" // 常规字符串let dir = @"C:"FS"FP" // 逐字字符串let bytes = "bytes"B // byte 数组let xA = 0xFFy // sbyte, 16进制表示let xB = 0o777un // unsigned native-sized integer,8进制表示let print x = printfn "%A" xlet main = print message; print dir; print bytes; print xA; print xB; main Printf函数通过F#的反射机制和.NET的ToString方法来解析“%A”模式,适用于任何类型的值,也可以通过F#中的print_any和print_to_string函数来完成类似的功能。值和函数(Values and Functions) 在F#中函数也是值,F#处理它们的语法也是类似的。 let n = 10let add a b = a + blet addFour = add 4let result = addFour n printfn "result = %i" result 可以看到定义值n和函数add的语法很类似,只不过add还有两个参数。对于add来说a + b的值自动作为其返回值,也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说,它定义在add的基础上,它只向add传递了一个参数,这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念,F(x, y) = x + y,G(y) = F(4, y),实际上G(y) = 4 + y,G也是一个函数,它接收一个参数,这个地方是不是很类似?这种只向函数传递部分参数的特性称为函数的柯里化(curried function)。 当然对某些函数来说,传递部分参数是无意义的,此时需要强制提供所有参数,可是将参数括起来,将它们转换为元组(tuple)。下面的例子将不能编译通过: let sub(a, b) = a - blet subFour = sub 4 必须为sub提供两个参数,如sub(4, 5),这样就很像C#中的方法调用了。 对于这两种方式来说,前者具有更高的灵活性,一般可优先考虑。 如果函数的计算过程中需要定义一些中间值,我们应当将这些行进行缩进: let halfWay a b = let dif = b - a let mid = dif / 2 mid + a 需要注意的是,缩进时要用空格而不是Tab,如果你不想每次都按几次空格键,可以在VS中设置,将Tab字符自动转换为空格;虽然缩进的字符数没有限制,但一般建议用4个空格。而且此时一定要用在文件开头添加#light指令。作用域(Scope)作用域是编程语言中的一个重要的概念,它表示在何处可以访问(使用)一个标识符或类型。所有标识符,不管是函数还是值,其作用域都从其声明处开始,结束自其所处的代码块。对于一个处于最顶层的标识符而言,一旦为其赋值,它的值就不能修改或重定义了。标识符在定义之后才能使用,这意味着在定义过程中不能使用自身的值。 let defineMessage = let message = "Help me" print_endline message // error 对于在函数内部定义的标识符,一般而言,它们的作用域会到函数的结束处。 但可使用let关键字重定义它们,有时这会很有用,对于某些函数来说,计算过程涉及多个中间值,因为值是不可修改的,所以我们就需要定义多个标识符,这就要求我们去维护这些标识符的名称,其实是没必要的,这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型,但F#仍能确保类型安全。所谓类型安全,其基本意义是F#会避免对值的错误操作,比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。 let changeType = let x = 1 let x = "change me" let x = x + 1 print_string x 在本例的函数中,第一行和第二行都没问题,第三行就有问题了,在重定义x的时候,赋给它的值是x + 1,而x是字符串,与1相加在F#中是非法的。 另外,如果在嵌套函数中重定义标识符就更有趣了。 let printMessages = let message = "fun value" printfn "%s" message; let innerFun = let message = "inner fun value" printfn "%s" message innerFun printfn "%s" message printMessages 打印结果: fun value inner fun valuefun value 最后一次不是inner fun value,因为在innerFun仅仅将值重新绑定而不是赋值,其有效范围仅仅在innerFun内部。递归(Recursion)递归是编程中的一个极为重要的概念,它表示函数通过自身进行定义,亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。 使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数: let rec factorial x = match x with | x when x < 0 -> failwith "value must be greater than or equal to 0" | 0 -> 1 | x -> x * factorial(x - 1) 这里使用了模式匹配(F#的一个很棒的特性),其C#版本为: public static long Factorial(int n) { if (n < 0) { throw new ArgumentOutOfRangeException("value must be greater than or equal to 0"); } if (n == 0) { return 1; } return n * Factorial (n - 1); } 递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心,可能会写出不能终止的递归。匿名函数(Anonymous Function) 定义函数的时候F#提供了第二种方式:使用关键字fun。有时我们没必要给函数起名,这种函数就是所谓的匿名函数,有时称为lambda函数,这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数,通常就不需要起名。在后面的“列表”一节中你会看到这样的例子。除了fun,我们还可以使用function关键字定义匿名函数,它们的区别在于后者可以使用模式匹配(本文后面将做介绍)特性。看下面的例子: let x = (fun x y -> x + y) 1 2let x1 = (function x -> function y -> x + y) 1 2let x2 = (function (x, y) -> x + y) (1, 2) 我们可优先考虑fun,因为它更为紧凑,在F#类库中你能看到很多这样的例子。 注意:本文中的代码均在F# 1.9.4.17版本下编写,在F# CTP 1.9.6.0版本下可能不能通过编译。 F#系列随笔索引页面