结论:script-src 'nonce-随机值' 允许带匹配 nonce 属性的 <script> 执行,随机值每次响应变化,攻击者注入的标签猜不到 nonce;'sha256-摘要' 按脚本内容哈希白名单,内容变哈希变。nonce 适合服务端动态渲染,hash 适合少量静态内联脚本(哈希列表要枚举每个脚本)。'unsafe-inline' 直接放行所有内联脚本——而 XSS 注入的脚本恰恰是内联的,CSP 形同虚设,只剩外联资源限制。

展开:实践决策:1)nonce 实现纪律——每次响应加密级随机生成(≥128 位)、禁止复用(复用 nonce 可被注入者复用),模板引擎自动给合法 <script> 加 nonce 属性(Rails/Next.js 有现成支持);注意 'strict-dynamic' 与 nonce 搭配可让可信脚本动态加载的子脚本免白名单,大幅简化大型应用落地。2)hash 的维护成本——改一个字符就要改响应头,适合 CSP 由构建工具生成的场景(CSP 写在 meta 标签或静态头里);注意 hash 对 event handler 属性(onclick)在 CSP3 下用 'unsafe-hashes',尽量重构掉。3)为什么 unsafe-inline 常见——历史应用内联脚本/event handler 太多,重构成本高;渐进路径是先 Report-Only 收集违规,逐批迁移脚本到外联文件 + nonce。易错点:nonce 通过 URL 参数/响应注入泄露(页面把 nonce 反射给攻击者构造的标签);strict-dynamic 下 host 白名单被忽略,理解策略组合再上线。

Content-Security-Policy: script-src 'nonce-4Ae98b3...' 'strict-dynamic'; object-src 'none'; base-uri 'self'

追问方向:Trusted Types 与 CSP 的分工(DOM sink 层 vs 加载层)、report-uri/report-to 的隐私与噪声治理。