COS q-signature 签名原理:Clara 原生实现的步骤拆解
学完这篇,你能搞清楚腾讯云 COS 的 q-signature 到底由哪几段拼成、每一步用什么算法,以及 Clara 在不装 SDK 的前提下是怎么把这套签名原生实现出来的。
第一步:先看清一张签名的长相
COS 每次请求都要带 `Authorization` 头(或者把签名拼进 URL 做预签名),它的长相是固定的:
q-sign-algorithm=sha1&q-ak=AKIDxxxx&q-sign-time=1700000000;1700000600&q-key-time=1700000000;1700000600&q-header-list=host&q-url-param-list=&q-signature=xxxxxxxx
七个字段里,`q-ak`、`q-sign-time`、`q-key-time`、两个 list 你都能直接写出来,只有 `q-signature` 是需要计算的。
注意:`q-sign-time` 的格式是"起始秒;结束秒",单位是秒。写成毫秒是最常见的翻车点。两个时间通常设成一样,有效期按需给(预签名 URL 建议几分钟)。
第二步:在后台把密钥填好
进入后台「系统设置→云存储」,填好 SecretId、SecretKey、Bucket、Region 和访问域名,然后打开云存储开关。
SecretKey 是唯一的签名原料,只能待在服务端,绝不能下发到浏览器。
第三步:派生 SignKey
COS 不直接用 SecretKey 签名,而是先做一次 HMAC 派生:
SignKey = HMAC-SHA1(SecretKey, q-key-time) // 取十六进制小写
Clara 不需要 Composer 装 SDK,PHP 内置函数就够:
$signKey = hash_hmac('sha1', $keyTime, $secretKey);
注意:`hash_hmac($algo, $data, $key)` 的参数顺序是「数据在前、密钥在后」,跟直觉反着来,写反了签名永远对不上。
第四步:拼 HttpString
HttpString 是签名的主体,四行内容、三个换行:
HttpString =
strtolower($method) . "\n" .
$uriPathname . "\n" .
$urlParams . "\n" .
$headers . "\n"
- `uriPathname`:以 `/` 开头,做 RFC3986 编码。PHP 用 `rawurlencode`,别用 `urlencode`(空格会变成 `+`)
- `urlParams`:所有 query 参数按 key 字典序排列,key 和 value 都要编码,拼成 `k=v&k=v`;没有就留空
- `headers`:参与签名的头(至少包含 `host`),key 全部小写并按字典序排,格式 `key=编码后的值`
注意:只把真正参与签名的头写进 `headers` 和 `q-header-list`,两边必须一致。多写一个或少写一个都会签名失败。
第五步:拼 StringToSign
StringToSign = "sha1\n" . $qSignTime . "\n" . sha1($httpString) . "\n"
这里的 `sha1()` 同样取十六进制小写。
第六步:算出 Signature
Signature = HMAC-SHA1(SignKey, StringToSign) // 十六进制小写
$signature = hash_hmac('sha1', $stringToSign, $signKey);
第七步:拼回 Authorization
把算好的 `q-signature` 填回第一步那个串,放进请求头 `Authorization` 即可。如果要做前端直传,就把它拼成 query 参数,形成一条带有效期的预签名 URL。
第八步:验证与排错
收到 `SignatureDoesNotMatch` 时,按顺序查这五项:
- 时间戳是不是秒
- URI 是不是 `rawurlencode` 编码过、且以 `/` 开头
- header 的 key 是不是全小写并按字典序排
- 换行符数量(HttpString 结尾那一个 `\n` 最容易漏)
- 服务器时间是否同步(NTP),偏几分钟就可能落在有效期外
注意:最有效的调试手段是把 HttpString 和 StringToSign 原样打印出来看,肉眼扫一遍往往就发现问题了。
第九步:Clara 这边的落地方式
- 不引 SDK:全程用 PHP 内置的 `hash_hmac` / `sha1` / `rawurlencode`,无 Composer、无编译缓存
- 配置即生效:后台保存密钥后,下一次上传就用新配置,不需要清缓存
- 密钥不出服务端:前端拿到的要么是签名后的请求头,要么是短时效的预签名 URL
- 权限收敛:预签名 URL 的 `q-key-time` 设短一些,过期即失效,避免链接被转发滥用
小结
- q-signature 的核心就三步 HMAC:派生 SignKey → 签 StringToSign → 得出 Signature
- 中间那层 HttpString 是"签了哪些东西"的清单,method、路径、参数、header 四段缺一不可
- 出错九成集中在三处:时间戳单位、URL 编码方式、header 是否小写并排序
- Clara 靠 PHP 内置函数原生实现,不装 SDK、保存即生效,服务器时间记得同步
转载请注明出处,版权归原作者所有。
星耀SVIP
管理员
黑卡会员





