签名 URL 刷新导致审批失效?别急着删掉所有 query

签名 URL 刷新导致审批失效?别急着删掉所有 query

一个真实而隐蔽的失败是:平台草稿连续两次回读,标题、正文和图片对象都相同,内容 SHA 却不一样。原因不是有人改稿,而是图片 CDN 每次返回了新的过期时间和签名参数。

如果批准令牌绑定原始 Markdown SHA,签名刷新会让刚签发的批准立即失效;如果为了省事删除所有 URL 查询参数,又可能把本应不同的资源合并。这个问题的核心不是"哈希算法怎么选",而是安全边界应该忽略什么、继续绑定什么。

冲突:密码学正确,业务语义却错位

SHA-256 对一个字符的变化都敏感,这是优点。可审批系统关心的可能是"图片对象有没有换",而不是"访问这个对象的短期凭证有没有刷新"。

因此需要同时承认两件事:

  • 原始 Markdown 的确变了,不能伪装成字节完全一致。
  • 如果只变了受信任图片 URL 的短期签名,发布对象可能仍是同一个。

把两个判断压成一个 SHA,迟早会让存储完整性和业务身份互相打架。

推荐决策:双哈希,而不是放宽一个哈希

我的推荐是保留两条证据链:

python 复制代码
strict_sha = sha256(raw_markdown)
approval_sha = sha256(canonicalize_signed_images(raw_markdown))

strict_sha 服务于存储、审计和逐字回读;approval_sha 只服务于已经定义过等价关系的批准或幂等边界。批准记录仍绑定文章 ID、revision 和草稿 ID,稳定摘要不能单独成为通行证。

规范化函数也必须是窄能力:只处理 Markdown 图片 URL,只接受 HTTPS,只命中明确的 CDN 域名,并且只删除已经验证会刷新的签名字段。

为什么不能直接 url.split('?')[0]

因为 query 未必都是凭证。尺寸、格式、语言、版本甚至对象选择都可能由 query 决定。下面三种变化必须区分:

  1. signatureexpires 刷新:在白名单契约下可以视为同一对象。
  2. /bucket/a.png 变成 /bucket/b.png:对象变了,必须拒绝旧批准。
  3. ?version=1 变成 ?version=2:如果版本影响内容,也必须拒绝。

安全规范化不是"去掉噪声",而是把经过证据确认的易变凭证与资源身份分离。

最小实现与关键测试

python 复制代码
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit

EPHEMERAL = {"signature", "expires", "policy"}
TRUSTED = {"img.example.com"}

def canonical_url(url: str) -> str:
    parsed = urlsplit(url)
    if parsed.scheme != "https" or parsed.hostname not in TRUSTED:
        return url
    stable_query = [
        (key, value)
        for key, value in parse_qsl(parsed.query, keep_blank_values=True)
        if key not in EPHEMERAL
    ]
    return urlunsplit(
        (parsed.scheme, parsed.netloc, parsed.path, urlencode(stable_query), "")
    )

测试不能只覆盖"签名刷新后相等",还必须证明边界没有被放宽:

  • 域名改变,稳定摘要必须改变。
  • 对象路径改变,稳定摘要必须改变。
  • 正文任意字符改变,稳定摘要必须改变。
  • 保留型 query 改变,稳定摘要必须改变。
  • 规范化执行两次与执行一次结果相同。

失败恢复怎么做

即使摘要稳定,发布结果未知时也不能重放批准。正确顺序仍是:先读草稿或目标对象的当前状态;若已经生成文章 ID,就验证审核页或公开页;只有明确未提交,才基于当前 revision 重新批准。

这能防止两个相反的问题:签名刷新造成假冲突,以及网络超时造成重复提交。

收束

内容指纹不是纯技术细节,而是业务身份的可执行定义。设计它时最该问的不是"用什么哈希",而是"哪些变化代表换了对象,哪些只是访问凭证刷新"。

一个可靠答案通常是双哈希加窄规范化:严格证据不丢,业务批准不被临时签名误伤,任何域名、对象路径和正文变化仍然 fail closed。

发布前门禁

  • 重点呈现方案冲突与取舍
  • 保留严格 SHA 与稳定 SHA 两套证据
  • 对域名、对象路径和正文变化保持拒绝
  • 未把单个平台现象夸大为所有 CDN 的统一规则
相关推荐
BullSmall3 小时前
第三方软件安全-Dependency‑Track Docker 部署
安全·docker·容器
AImatters3 小时前
国产算力底座,支撑油气储运数字化迈过关键分水岭
安全·cpu·算力·海光·油气储运
傲笑风4 小时前
【openvino】tinybert基于openvino服务化部署(四)
人工智能·python·自然语言处理·nlp·bert·openvino
维基框架4 小时前
WIKI 知识库 v1.1.1 正式发布
人工智能·python
叠叠乐6 小时前
中国移动家庭云电脑window关闭所有安全脚本
安全
Jmyd01237 小时前
实训室的 3D 模型涉及肖像文物,数据安全与合规怎么做?
安全·3d·数据安全·虚拟实训
芯盾时代7 小时前
《金融业网络安全管理办法(征求意见稿)》全条款深度拆解(三)
网络·安全·网络安全
敢敢是只喵i7 小时前
一个本地 AI Agent 要操作多个门店或 SaaS 账号,应该怎样安全切换身份?
人工智能·安全·ai·系统架构·业界资讯
Acrel12348 小时前
DC800V 大规模落地,算力机房安全该如何保障
安全
谢白羽8 小时前
SGLang的AWQ量化笔记
笔记·python·sglang