首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >COS 预签名下载排障:GET 请求、双重有效期与凭证泄露边界

COS 预签名下载排障:GET 请求、双重有效期与凭证泄露边界

原创
作者头像
一只特立独行的兔先生
发布于 2026-10-20 10:07:48
发布于 2026-10-20 10:07:48
900
举报

结论:链接生成成功,不等于下载授权成功

COS 预签名 URL 可以让没有云账号凭据的调用方,在限定时间内下载指定对象。但它不是一次性链接,也不会自动替业务系统判断“这个用户能否下载这份文件”。拿到有效链接的人即可使用它,因此应把完整 URL 当作短期访问凭证保护。

排查下载失败时,先分清三层:业务是否允许签发、签名与临时凭据是否有效、实际 HTTP 请求是否与签名条件一致。不要一遇到 403 就延长有效期或把存储桶改成公有读。

一、用私有测试对象建立最小链路

准备一个私有桶中的非敏感小文件,例如 diagnostics/sample.txt。确认桶地域、完整桶名(含 APPID)和对象键。对象键是 COS 中的完整名称,不是本地路径,也不要自行添加开头的斜杠。

安装 Python SDK:

代码语言:bash
复制
python -m pip install cos-python-sdk-v5

以下脚本使用已经取得的临时凭据。环境变量 COS_SECRET_ID、COS_SECRET_KEY、COS_SESSION_TOKEN 分别保存临时 SecretId、临时 SecretKey 和 Token;不要把密钥直接粘进源码或提交到仓库。

代码语言:python
复制
import os
from qcloud_cos import CosConfig, CosS3Client

config = CosConfig(
    Region=os.environ["COS_REGION"],
    SecretId=os.environ["COS_SECRET_ID"],
    SecretKey=os.environ["COS_SECRET_KEY"],
    Token=os.environ["COS_SESSION_TOKEN"],
    Scheme="https",
)
client = CosS3Client(config)
url = client.get_presigned_url(
    Method="GET",
    Bucket=os.environ["COS_BUCKET"],
    Key="diagnostics/sample.txt",
    Expired=120,
)
# 仅在隔离的本地诊断终端输出;不要接入生产日志。
print(url)

这里的 120 是示例签名时长,单位为秒,不是平台统一推荐值。临时凭据必须具备测试对象的读取权限;代码不会创建权限,也不会证明对象存在。

二、按原始请求验证,不要用 HEAD 替代 GET

在可信本机把刚生成的完整链接放入 SIGNED_URL,立即执行:

代码语言:bash
复制
curl --silent --show-error \
  --dump-header response.headers \
  --output response.body \
  --write-out 'HTTP %{http_code}\n' \
  "$SIGNED_URL"

这是 Bash 示例,变量必须带引号,否则 URL 中的 & 可能被 shell 当作控制符。不要把完整链接放进工单、聊天截图或公共在线 URL 检测网站。

预期结果是 HTTP 200,且 response.body 与测试文件内容一致。失败时查看响应头与错误响应正文,并保留请求标识用于排查。curl 未启用失败状态选项时,退出码为零也可能对应 HTTP 错误,因此必须检查 HTTP 状态。

不要改成 curl -I:它发送 HEAD,而这里签发的是 GET。也不要先替换成 CDN 域名、手动重新编码对象路径或拼接业务参数。先验证 SDK 生成的原始地址,再逐项加入代理和前端链路,才能找到是哪一层改变了请求。

三、有效期由两个时钟共同约束

使用临时密钥时,URL 受到签名有效期和临时凭据有效期共同限制。签名还没过期,不代表临时凭据仍然有效;把 Expired 调大也无法延长临时凭据寿命。

服务端应保存临时凭据的过期时间,按以下规则决定是否签发:

  • 剩余时间 = 临时凭据过期时间 - 当前时间。
  • 允许时长 = min(业务链接时长, 剩余时间 - 安全余量)。
  • 允许时长不大于零:先刷新凭据,不签发链接。
  • 否则:用允许时长生成预签名 URL。

安全余量用于覆盖请求排队与网络延迟,应结合业务选择,不必照搬固定数字。签名服务器也要保持时间同步。不要只缓存一个 URL 再长期复用,更不要把临时凭据的获取时间误认为过期时间。

四、把排障证据留对地方

建议按顺序检查:

  • 原始 GET 是否成功;失败则先读 COS 返回的错误码,不凭 403 猜测唯一原因。
  • 桶名、地域、对象键是否匹配;测试对象是否仍存在。
  • 临时凭据是否携带 Token,凭据权限是否覆盖该对象。
  • 签名与凭据是否都在有效期内,签名机器时间是否正常。
  • 经前端、反向代理或 CDN 后,方法、路径、查询参数及参与签名的请求头是否改变。

生产日志只记录业务请求号、签发时间、期限、HTTP 状态和必要的错误码。对象键如果含个人信息,也需要脱敏。不要记录完整预签名 URL、Token 或 SecretKey。

五、业务侧仍需独立授权

下载接口应先认证用户,再验证其对业务文件的权限,最后从服务端可信映射取得对象键并签发。不能让用户任意提交桶名和对象键,再由高权限服务端无条件签名。

验收至少覆盖三种情况:有权限用户可下载正确内容;无权限用户在签发阶段被拒绝;短期链接过期后重新发起请求无法继续取得对象。过期不会收回已经下载的文件,也不要把它理解成强制中断进行中传输的计时器。

本文提供可复现步骤与预期结果,不代表已经在读者的桶、权限策略和网络链路上执行验证。

参考文档

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 结论:链接生成成功,不等于下载授权成功
  • 一、用私有测试对象建立最小链路
  • 二、按原始请求验证,不要用 HEAD 替代 GET
  • 三、有效期由两个时钟共同约束
  • 四、把排障证据留对地方
  • 五、业务侧仍需独立授权
  • 参考文档
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档