首次MISS响应里的script nonce与CSP头一致,HIT之后却不一致或干脆缺失。nonce必须每个响应随机,不能随整页HTML被FPC固定缓存。

复现与判断

我保留了一个失败样本,并用同样输入在无缓存或单节点条件下再跑一遍。这样可以把前端假象、缓存和真正的数据问题分开。

数据库和日志对照

  • 连续请求同一URL,对比CSP响应头和script标签nonce。
  • 用X-Magento-Cache-Debug确认一次MISS、一次HIT。
curl -sI https://shop.example.com/page | grep -i "content-security|x-magento-cache"
curl -s https://shop.example.com/page | grep -o "nonce=.[^ >]*" | head
grep -R "nonce" app/code/Vendor app/design -n

为了避免把环境差异当成根因,我会先在预发布或数据库副本复现;涉及订单、库存和支付的操作,正式环境只做只读核对,修复脚本必须带明确的订单号或SKU范围。

这次的修法

不要在可缓存block里手工生成nonce。Magento支持的版本使用SecureHtmlRenderer渲染内联脚本,让框架按响应处理;更稳妥的是把脚本移到外部静态文件并用CSP白名单允许其来源。清理FPC后验证HIT响应。若反代覆盖CSP头,移除重复头。

修改范围

  • 先在单个SKU、单个订单或单个Store验证。
  • 保留可回退的旧配置,不覆盖原始证据。
  • 需要批量处理时分批提交并输出成功/失败清单。

验证结果

  • MISS和HIT都不报CSP错误
  • 页面只有一份CSP策略
  • 内联脚本使用框架生成方式
  • Report-Only与Enforce环境一致

验收不只看后台提示“成功”。我还会从前台/API再走一次真实链路,并在下一轮cron、索引或缓存命中后重复检查,确认不是短暂正常。

顺手记下

把unsafe-inline加回去能消错但等于放弃这部分CSP防护。