AI 供应链安全:模型制品签名校验与 Redis 缓存落地

被投毒的不是代码,而是权重文件

一个反直觉的事实是:AI 系统最脆弱的一环通常不是推理服务,而是构建流水线拉下来的那个 .safetensors 或 requirements.txt。传统软件供应链攻击要拿到代码执行权限才能作恶,而 AI 供应链攻击只要让模型"表现差一点",或者对特定输入输出特定内容就够了。你的单元测试会全绿,监控曲线平滑,问题只会在三个月后的一条业务告警里浮现。

AI 特有的三个攻击面决定了防御重点与传统软件供应链不同:

  • 反序列化执行 :PyTorch 的 .bin/.pt 走 pickle,加载即执行任意代码。换成 safetensors(Hugging Face 主推的纯张量只读格式)能整类消除这条路径,代价是并非所有历史模型都有对应转换。
  • 权重后门 :攻击者不需要执行任何代码,发布一个"效果更好"的微调模型,里面埋触发词即可。哈希校验对这类攻击完全无效------文件确实是你签名拉下来的那一个,只是它的语义被污染了。
  • 配置与模板 :tokenizer 的 special tokens、chat template 里的 Jinja 模板(可注入)、requirements.txt 的传递依赖,都位于签名覆盖范围之外。

所以第一件要想清楚的事:签名校验解决的是"来源可信 + 内容未被篡改",它不解决"模型语义是否安全"。把两者混为一谈,是绝大多数落地失败的起点。

概念对齐:摘要、来源证明、签名

四个词必须分清,否则后面的策略没法写:

  • 制品摘要(digest):对文件内容做 sha256。名字和 tag 可变,digest 不可变。所有缓存、策略、审计都必须以 digest 为主键。
  • 来源证明(provenance):in-toto 格式的 attestation,描述"谁、用什么构建系统、从哪个 commit 构建的"。SLSA v1.0 规范把它拆成 build definition 与 run details 两部分,等级越高,构建过程越不可被单人篡改。
  • 签名(signature):Sigstore cosign 的 keyless 模式用 CI 的 OIDC 身份签发短期证书,签名条目写入透明日志 Rekor,从而把"信任"从一把长期密钥转移到"这个 GitHub Actions workflow 的身份"上。
  • 策略(policy) :准入判断,形如"签名者身份必须匹配 acme/ml-pipeline,issuer 必须是 GitHub OIDC,且必须存在 Rekor 条目"。

适用边界要讲清楚:签名只保证"这是我签的",不保证"这是安全的"。SLSA 等级描述的是构建过程可信度,不是代码质量。指望签名挡住投毒,等于指望门锁挡住屋里的内鬼。

机制拆解:从 OIDC 签名到 Redis 缓存校验

完整的准入链路是这样的:

  1. 拉取前先解析出制品 digest,而不是先下载再算;
  2. 用 cosign verify-blob 校验签名、证书身份、OIDC issuer 与 Rekor 条目;
  3. 校验结论按 digest 写入 Redis,TTL 与证书有效期或策略窗口对齐;
  4. 后续流水线命中缓存直接放行,避免每次构建都打一次 Rekor(透明日志查询是网络调用,延迟不可控);
  5. 密钥泄露或策略升级时,通过 pub/sub 广播删除对应 key,保证吊销能传播。

Redis 7.4 引入的 hash 字段级过期(HEXPIRE / HTTL)在这里刚好合用:一个 digest 下挂多个结论字段------签名校验、SBOM 检查、恶意权重扫描------它们的最长有效期完全不同,字段级 TTL 比给整个 key 设一个折中的过期时间更准确。

python 复制代码
import subprocess, redis

r = redis.Redis(host="redis", port=6379, decode_responses=True)
IDENTITY = "--certificate-identity-regexp=^https://github.com/acme/ml-pipeline/"
ISSUER   = "--certificate-oidc-issuer=https://token.actions.githubusercontent.com"

def verify(digest: str, blob: str) -> bool:
    key = f"attest:{digest}"                 # 主键只认 digest,绝不用模型名或 tag
    if r.hget(key, "sig") == "ok":           # 命中缓存,跳过 Rekor 查询
        return True
    p = subprocess.run(
        ["cosign", "verify-blob",
         "--signature", f"{blob}.sig", "--certificate", f"{blob}.pem",
         *IDENTITY.split(), *ISSUER.split(), blob],
        capture_output=True)
    if p.returncode != 0:                    # 校验失败不写缓存,防止负结论被固化
        return False
    r.hset(key, mapping={"sig": "ok", "policy": "v3"})
    # 原生命令:HEXPIRE attest:<digest> 86400 FIELDS 1 sig
    r.hexpire(key, 86400, "sig")             # 签名结论 24h 后强制重验
    r.hexpire(key, 604800, "policy")         # 策略版本结论 7d
相关推荐
简创AIGC陶先生1 小时前
【直播切片工作台】第17章:JWT 鉴权:签发、解析与中间件
github
Funlang1 小时前
Fun 的工具链,自己写自己
github
云南新人和数采集团1 小时前
DeepSeek Harness 开源贡献手记:从入门到合入主线
python·开源·github
曹牧3 小时前
电子邮件服务器拒绝了您的用户名
github
wflynn3 小时前
GitHub 今日推荐|Snapintosh:用 ARM EL2 监控器骗过内核,让骁龙芯片笔记本跑 macOS
python·开源·github
钱栈up3 小时前
GitHub 热榜上手|ArtCraft:+13,572 star 的 AI 创作 IDE
人工智能·github
阿里嘎多学长5 小时前
2026-10-23 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Brookty5 小时前
Git 与 GitHub|第一阶段:仓库、版本历史与 Git 对象模型(上篇)
git·github
miofly5 小时前
GitHub 日榜趋势速报 | 2026-10-24
开源·github