签名 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. signature、expires 刷新:在白名单契约下可以视为同一对象。
  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 的统一规则
相关推荐
蜗牛互联网2 小时前
Python调用Gemini Structured Outputs实现工单路由门禁
java·开发语言·人工智能·python
罗斯8392 小时前
Datalog与安全分析
算法·安全·网络安全
TomEval2 小时前
【测AI】第12篇:NLP / CV / 语音 —— 三大 AI 方向速通
人工智能·python·自然语言处理·aigc·测试用例
SEO_juper2 小时前
给网页做可引用性评分:判断内容够不够让 AI 引用(GEO 工具,附代码)
开发语言·人工智能·爬虫·python·seo·独立站
橙色云-智橙协同研发2 小时前
电子高科技行业:机械与电子(MCAD & ECAD)如何协同?
大数据·运维·服务器·人工智能·安全
AI直播技术杂谈2 小时前
无人直播中控的硬件底线,旧电脑要满足哪些条件
网络·python·ai·云计算
Helix2502 小时前
Python数据分析实战:Pandas清洗豆瓣短评与情感分析完整指南
python·pandas·数据清洗·情感分析··snownlp·文本数据处理
上海广测检测科技有限公司2 小时前
音响网络安全认证:联网音频设备的全球合规法规与测试要点解读
网络·经验分享·安全
Xudde.2 小时前
AI-Web1 靶机渗透测试(Vulnhub Writeup)
笔记·学习·安全·web安全
黄聪的笔记本2 小时前
阿里云香港服务器Workbench远程连接,没法SSH连接,22端口安全组已经放开
服务器·安全·阿里云