
COS 预签名 URL 可以让没有云账号凭据的调用方,在限定时间内下载指定对象。但它不是一次性链接,也不会自动替业务系统判断“这个用户能否下载这份文件”。拿到有效链接的人即可使用它,因此应把完整 URL 当作短期访问凭证保护。
排查下载失败时,先分清三层:业务是否允许签发、签名与临时凭据是否有效、实际 HTTP 请求是否与签名条件一致。不要一遇到 403 就延长有效期或把存储桶改成公有读。
准备一个私有桶中的非敏感小文件,例如 diagnostics/sample.txt。确认桶地域、完整桶名(含 APPID)和对象键。对象键是 COS 中的完整名称,不是本地路径,也不要自行添加开头的斜杠。
安装 Python SDK:
python -m pip install cos-python-sdk-v5以下脚本使用已经取得的临时凭据。环境变量 COS_SECRET_ID、COS_SECRET_KEY、COS_SESSION_TOKEN 分别保存临时 SecretId、临时 SecretKey 和 Token;不要把密钥直接粘进源码或提交到仓库。
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 是示例签名时长,单位为秒,不是平台统一推荐值。临时凭据必须具备测试对象的读取权限;代码不会创建权限,也不会证明对象存在。
在可信本机把刚生成的完整链接放入 SIGNED_URL,立即执行:
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 调大也无法延长临时凭据寿命。
服务端应保存临时凭据的过期时间,按以下规则决定是否签发:
安全余量用于覆盖请求排队与网络延迟,应结合业务选择,不必照搬固定数字。签名服务器也要保持时间同步。不要只缓存一个 URL 再长期复用,更不要把临时凭据的获取时间误认为过期时间。
建议按顺序检查:
生产日志只记录业务请求号、签发时间、期限、HTTP 状态和必要的错误码。对象键如果含个人信息,也需要脱敏。不要记录完整预签名 URL、Token 或 SecretKey。
下载接口应先认证用户,再验证其对业务文件的权限,最后从服务端可信映射取得对象键并签发。不能让用户任意提交桶名和对象键,再由高权限服务端无条件签名。
验收至少覆盖三种情况:有权限用户可下载正确内容;无权限用户在签发阶段被拒绝;短期链接过期后重新发起请求无法继续取得对象。过期不会收回已经下载的文件,也不要把它理解成强制中断进行中传输的计时器。
本文提供可复现步骤与预期结果,不代表已经在读者的桶、权限策略和网络链路上执行验证。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。