前言
无论是在app中播放视频,还是在网页上嵌入视频,我们都希望该视频只能在自家的网站或者app中才可以被下载或者被观看
为了防止视频被盗链,我们除了在请求头Header里使用Authorization字段防盗链之外,还可以在URL中加入签名信息,
这样我们就还可以把该视频文件的URL分享给其他人,并且实现限时授权访问了
用户签名验证机制
OSS通过使用AccessKeyId / AccessKeySecret对称加密的方法来验证某个请求的发送者身份。
AccessKeyId用于标示用户,
AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret必须保密,只有用户和OSS知道。
AccessKey 根据所属账号的类型有所区分
阿里云账户AccessKey:每个阿里云账号提供的AccessKey拥有对拥有的资源有完全的权限 (慎用)
★ RAM账户AccessKey:RAM账户由阿里云账号授权生成,所拥的AccessKey拥有对特定资源限定的操作权限(推荐)
STS临时访问凭证:由阿里云账号或RAM账号生成,所拥的AccessKey在限定时间内拥有对特定资源限定的操作权限。过期权限收回。
验证思路:
1. 当用户想以个人身份向OSS发送请求时,需要首先将发送的请求按照OSS指定的格式生成签名字符串;
2. 然后使用AccessKeySecret对签名字符串进行加密产生验证码。
3. OSS收到请求以后,会通过AccessKeyId找到对应的AccessKeySecret,以同样的方法提取签名字符串和验证码,如果计算出来的验证码和提供的一样即认为该请求是有效的;
否则,OSS将拒绝处理这次请求,并返回HTTP 403错误。
URL最终效果示例:
http://beyond-cubic.oss-cn-hangzhou.aliyuncs.com/video_01.mp4?OSSAccessKeyId=你的KeyId&Expires=1141889120&Signature=FX6Xd69gednlZ7Ga%2BIYNEm5NWos%3D
http://beyond-cubic.oss-cn-hangzhou.aliyuncs.com/video_01.mp4?
OSSAccessKeyId = 你的KeyId
&
Expires = 1141889120
&
Signature = FX6Xd69gednlZ7Ga%2BIYNEm5NWos%3D
URL签名解释说明:
URL签名,必须至少包含OSSAccessKeyId、Expires和Signature三个参数。
★ OSSAccessKeyId 即密钥中的AccessKeyId。
★ Expires 这个参数的值是一个UNIX时间(自UTC时间1970年1月1号开始的秒数),一般是当前时间戳 + 200秒,用于标识该URL的超时时间。如果OSS接收到这个URL请求的时候晚于签名中包含的Expires参数时,则返回请求超时的错误码,即200秒后,该下载的url链接自动失效。
例如:当前时间是1535816060,开发者希望创建一个60秒后自动失效的URL,则可以设置Expires时间为1535816120。即: 该分享的下载链接只在1分钟内有效
★ Signature 表示签名信息。所有的OSS支持的请求 和 各种Header参数,在URL中进行签名的算法 和 在Header中包含签名的算法基本一样。
签名算法实现原理:
Signature = urlencode(base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ CONTENT-MD5 + "\n"
+ CONTENT-TYPE + "\n"
+ EXPIRES + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource)))
但是, 相比在Header中的签名验证, 普通的GET url 签名, 就简单得多了:
注意:
VERB就是“GET”或者”PUT”等
CanonicalizedResource就是/beyond-cubic/video_01.mp4之类,
/beyond-cubic是bucket的名称;
/video_01.mp4才是资源的路径
区别对比:
与在请求头header中包含签名的方式相比, URL中签名的主要不同点如下:
★ 通过URL包含签名时,之前的Date参数换成Expires参数。
★ 不支持同时在URL和Head中包含签名。
★ OSS服务器会先验证请求时间是否晚于Expires时间,然后再验证签名。
★ 将签名字符串放到url时,注意要对url进行urlencode
★ 如果传入的Signature,Expires,OSSAccessKeyId出现不止一次,以第一次为准。
- 临时用户URL签名时???,需要携带
security-token
,这个暂时没有用到 - 格式如下:
http://oss-example.oss-cn-hangzhou.aliyuncs.com/oss-api.pdf?OSSAccessKeyId=nz2pc56s936**9l&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D&security-token=SecurityToken
Python示例代码
URL中添加签名的python示例代码
注意: 下面的文件路径必须带在bucket名称喔~
比如: CanonicalizedResource = “/beyond-cubic/video_01.mp4”
bucket名称: /beyond-cubic
资源路径: /video_01.mp4
signature.py文件里的完整代码如下:
最终url地址如下:
细节分析
★ 使用在URL中签名的方式,会将你授权的数据在过期时间以内曝露在互联网上,请预先评估使用风险。
★ PUT和GET请求都支持在URL中签名。
★ 在URL中添加签名时,Signature,Expires,OSSAccessKeyId顺序可以交换,但是如果Signature,Expires,OSSAccessKeyId缺少其中的一个或者多个,返回403 Forbidden。错误码:AccessDenied。
★ 如果访问的当前时间晚于请求中设定的Expires时间,返回403 Forbidden。错误码:AccessDenied。
如果Expires时间格式错误,返回403 Forbidden。错误码:AccessDenied。
★ 如果URL中包含参数Signature,Expires,OSSAccessKeyId中的一个或者多个,并且Head中也包含签名消息,返回消息400 Bad Request。即不支持Url和Head同时验证! 错误码:InvalidArgument。
★ 生成签名字符串时,除Date被替换成Expires参数外,仍然包含content-type、content-md5等上节中定义的Header(只是为空罢了)(请求中虽然仍然有Date这个请求头,但不需要将Date加入签名字符串中)。
附录: 其他语言的SDK参考链接:
SDK | 方法 | 文件链接 |
---|---|---|
Java | OSSClient.generatePresignedUrl | OSSClient.java |
Python | Bucket.sign_url | api.py |
.Net | OssClient.GeneratePresignedUri | OssClient.cs |
PHP | OssClient.signUrl | OssClient.php |
JS | signatureUrl | object.js |
C | oss_gen_signed_url | oss_object.c |