签名算法

最近更新时间:2019-08-22 15:12:53

腾讯云对象存储提供多种语言 SDK,SDK 内置了生成签名的方法,详情请参考各语言 SDK 的生成签名章节。

签名鉴权

为什么需要鉴权?

业务端购买腾讯云(对象存储)服务,来作为其业务组成的一部分(云存储或内容分发加速),并最终提供给用户。所以当用户访问腾讯云服务时,需要先征得业务端的“许可”。那么,用户如何才能向腾讯云证明自己已经得到“访问许可”了呢?

简单的说,腾讯云和业务端约定了一套规则,通过这套规则,业务端可以产生一个“钥匙”。当用户需要访问业务端购买的腾讯云服务时,业务端会将这个钥匙传递给用户,然后用户拿着这个钥匙去向腾讯云“证明”自己已经拿到了“访问许可”。腾讯云收到用户的请求后,会先鉴别“钥匙”是否有效,若有效,则允许访问云服务,若无效,则返回 Authorization 错误消息。

这套规则,就是腾讯云的“鉴权系统”,这把“钥匙”,就是下文要解释的“签名”。

签名有哪几种?

签名本质上是一个加密的字符串,目前在腾讯云中,分为多次有效签名单次有效签名

多次有效签名:签名中部分不绑定文件 fileid ,部分绑定文件 fileid ,开启token防盗链的下载、文件简单上传、文件分片上传可以绑定 fileid,同时支持前缀匹配。多次有效签名需要设置一个大于当前时间的有效期,有效期内此签名可多次使用,有效期最长可设置三个月。

单次有效签名:签名中绑定文件 fileid ,有效期必须设置为0,此签名只可使用一次,且只能应用于被绑定的文件或文件夹操作。

哪些场景需要用到签名?

腾讯云对象存储(COS)对签名的适用场景做了如下限制:

场景 适用签名 签名中是否需要绑定 fileid
下载(不开启 token 防盗链) 不验证签名 -
下载(开启 token 防盗链) 多次有效签名 可选
简单上传文件 多次有效签名 可选
分片上传文件 多次有效签名 可选
查询目录、文件属性 多次有效签名
创建目录 多次有效签名
删除目录、文件 单次有效签名
更新文件属性 单次有效签名
移动(重命名)文件 单次有效签名

如何使用签名来完成鉴权?

腾讯云对象存储(COS)通过签名来验证请求的合法性。业务端通过将签名授权给用户端,使其具备上传下载及管理指定资源的权限。

当用户使用 RESTful API 对腾讯云对象存储资源进行操作时,必须要在每个 Http/Https 请求的 Header 中填写 Host 和 Authorization,其中的 Authorization 参数,即为“签名算法”最终得到的 sign 字符串。

参数名称 必选 类型 描述
Host String 文件云服务器域名,固定为[region].file.myqcloud.com
Authorization String 用户的有效签名,用于鉴权

腾讯云对象存储目前提供了 COS 签名工具 供用户生成签名,如有需要可前往使用。

签名算法

腾讯云的各类 SDK 已经提供了标准的签名计算方法,业务端只需填写相关参数,即可得到签名字符串。用户也可以根据 RESTful API 自行计算签名。

对于签名的计算过程,可简单分为如下三个步骤:获取签名所需信息,拼接明文字符串,将明文字符串转化为签名

获取签名所需信息

生成签名所需信息包括项目 ID(App Id),空间名称(Bucket,文件资源的组织管理单元),项目的 Secret ID 和 Secret Key。获取这些信息的方法如下:

1) 登录腾讯云对象存储,进入对象存储空间;

2) 如开发者未创建空间,可添加空间,空间名称(Bucket)由用户自行输入;

3) 单击【获取 API 密钥】,获取 App Id,Secret ID 和 Secret Key。

拼接明文字符串 Original

明文字符串 Original 按照签名的类型可划分为“多次”和“单次”有效签名。

拼接多次有效签名串 multi_effect_signature :

Original = "a=[appid]&b=[bucket]&k=[SecretID]&e=[expiredTime]&t=[currentTime]&r=[rand]&f="

拼接单次有效签名串 once_signature :

Original = "a=[appid]&b=[bucket]&k=[SecretID]&e=[expiredTime]&t=[currentTime]&r=[rand]&f=[fileid]"

签名串中各字段含义如下:

字段 解释
a 开发者的项目 ID,接入对象存储服务创建空间时系统生成的唯一标识项目的 ID,即 App Id
b 空间名称 Bucket
k 项目的 Secret ID
t 当前时间戳,是一个符合 Unix Epoch 时间戳规范的数值,单位为秒
e 多次有效签名时,e 为签名的失效时刻,是一个符合Unix Epoch时间戳规范的数值,单位为秒。e 的计算方式为 e = t + 签名有效时长。签名有效时长最大取值为7776000(90天);单次签名时,e 必须设置为0
r 随机串,无符号10进制整数,用户需自行生成,最长 10 位
f fileid ,唯一标识存储资源的相对路径。格式为 /appid/bucketname/dirname/[filename],并且需要对其中非 '/' 字符进行 UrlEncode 编码。 当操作对象为 文件夹时,filename 缺省。filename 中要包含文件后缀名。
注意:

  • 当签名类型需要绑定 fileid 时,f 字段请按要求赋值。
  • 拼接单次有效签名的签名串时,过期时间 e 必须设置为0,以保证此签名只能针对固定资源使用一次。
  • 拼接多次有效签名的签名串时,过期时间 e 的单位为秒,不同编程语言获得的系统 Unix 时间戳单位可能有所差异(例如 Java 是毫秒),但都请转化为秒。
  • 多次/单次有效签名的具体适用场景参见本文章节哪些场景需要用到签名?

将明文字符串转化为签名

拼接好签名的明文字符串 Original 后,用已经获取的 SecretKey 对明文串进行 HMAC-SHA1 加密,得到 SignTmp:

SignTmp = HMAC-SHA1(SecretKey, Original)

将密文串 SignTmp 放在明文串 Origin 前面,拼接后进行 Base64Encode 算法,得到最终的签名 Sign:

Sign = Base64 (append(SignTmp, Original))

注意:

  • 此处使用的是标准的 Base64 编码,不是 urlsafe 的 Base64 编码。
  • 由于使用了 HMAC 算法,计算 SignTmp 的结果为二进制字符串,因此建议将算法写在同一函数中实现。单独输出 SignTmp 可能导致拼接后的字符串有误。

示例

本节介绍生成签名的算法实例,实例中使用 PHP 语言(若开发者使用其他开发语言,请使用对应的函数)。

获取签名所需信息

获取得到的签名所需信息如下

项目 ID:200001

空间名称 Bucket:newbucket

Secret ID:AKIDUfLUEUigQiXqm7CVSspKJnuaiIKtxqAv

Secret Key:bLcPnl88WU30VY57ipRhSePfPdOfSruK

拼接签名串

拼接的多次有效签名串 multi_effect_signature 如下:

a=200001&b=newbucket&k=AKIDUfLUEUigQiXqm7CVSspKJnuaiIKtxqAv&e=1437995704&t=1437995644&r=2081660421&f=

拼接的单次有效签名串 once_signature 如下:

a=200001&b=newbucket&k=AKIDUfLUEUigQiXqm7CVSspKJnuaiIKtxqAv&e=0&t=1437995645&r=1166710792&f=/200001/newbucket/tencent_test.jpg

$appid = "200001";
$bucket = "newbucket";
$secret_id = "AKIDUfLUEUigQiXqm7CVSspKJnuaiIKtxqAv";
$secret_key = "bLcPnl88WU30VY57ipRhSePfPdOfSruK";
$expired = time() + 60;
$onceExpired = 0;
$current = time();
$rdm = rand();
$fileid = "/200001/newbucket/tencent_test.jpg";

$multi_effect_signature = 'a='.$appid.'&b='.$bucket.'&k='.$secret_id.'&e='.$expired.'&t='.$current.'&r='.$rdm.'&f=';

$once_signature=
'a='.$appid.'&b='.$bucket.'&k='.$secret_id.'&e='.$onceExpired.'&t='.$current.'&r='.$rdm.'&f='.$fileid;

生成签名

$multi_effect_signature = base64_encode(hash_hmac('SHA1', $multi_effect_signature, $secret_key, true).$multi_effect_signature);

$once_signature = base64_encode(hash_hmac('SHA1',$once_signature,$secret_key, true).$once_signature);

echo $multi_effect_signature."\n"; 

echo $once_signature."\n";

最终得到的多次有效签名为:

v6+um3VE3lxGz97PmnSg6+/V9PZhPTIwMDAwMSZiPW5ld2J1Y2tldCZrPUFLSURVZkxVRVVpZ1FpWHFtN0NWU3NwS0pudWFpSUt0eHFBdiZlPTE0NzA3MzcwMDAmdD0xNDcwNzM2OTQwJnI9NDkwMjU4OTQzJmY9

单次有效签名为:

CkZ0/gWkHy3f76ER7k6yXgzq7w1hPTIwMDAwMSZiPW5ld2J1Y2tldCZrPUFLSURVZkxVRVVpZ1FpWHFtN0NWU3NwS0pudWFpSUt0eHFBdiZlPTAmdD0xNDcwNzM2OTQwJnI9NDkwMjU4OTQzJmY9LzIwMDAwMS9uZXdidWNrZXQvdGVuY2VudF90ZXN0LmpwZw==