CSP 头部验证工具

粘贴 Content-Security-Policy 头部的值,一次性验证所有指令和来源值。可检测 unsafe-inline 等高风险设置、缺失的 default-src 兜底、指令名称拼写错误,并以可视化方式展示每个指令允许的来源。

使用技巧

  • CSP 通常以 HTTP 响应头的形式下发,但也可以通过 <meta http-equiv="Content-Security-Policy"> 标签设置(不过 report-uri 等部分指令在 meta 标签中不生效)。
  • 在生产环境正式启用 CSP 之前,建议先使用 Content-Security-Policy-Report-Only 头部——它只收集违规报告,方便你在不影响现有功能的前提下评估实际影响。
  • 通配符(*)和 'unsafe-inline' 虽然能让开发更省事,但会削弱 CSP 大部分的 XSS 防护能力,上线前务必收紧这类宽松策略。
  • 同一指令重复书写两次不会合并取值,只有第一次出现生效。如需追加或覆盖来源,请把所有值写在同一条指令中。
  • 浏览器 DevTools 控制台会以红色「Refused to load...」信息显示被拦截的资源,调试过严的 CSP 时应首先查看这里。

常见问题

CSP 会明确告诉浏览器,页面上允许从哪些来源加载脚本、图片、样式等资源。任何不在白名单内的资源(包括内联脚本)都会被阻止加载或执行,从而大幅降低 XSS 攻击执行攻击者控制脚本的风险。

有的——nonce 来源('nonce-<随机值>')和 hash 来源('sha256-<哈希值>')都可以实现这一点。只要在脚本标签上添加与响应头中一致的 nonce 属性,就能只允许这一特定标签执行,同时继续拦截其他未经授权的内联脚本。

这是因为该资源的来源不在白名单内,被 CSP 拦截了。浏览器控制台会显示类似「Refused to load...because it violates the following Content Security Policy directive」的消息,其中会标明具体的来源域名——将该来源添加到对应指令的白名单中即可解决。

通常是不够的。default-src 只是对未显式设置的指令起兜底作用。像 script-src、object-src 这类高风险指令,应各自明确且严格地配置,因为它们代表的攻击面远大于其他大多数指令。

两者都用于指定浏览器应将违规报告发送到哪里,但 report-uri 是较早的指令,直接指向一个上报用的 URL;report-to 则基于更新的 Reporting API,引用的是在另一个 Report-To 头部中定义好的命名分组。由于两者的浏览器支持情况不同,通常建议同时指定两者以确保兼容性。
ツールくん

闲话 ― CSP 为何诞生:仅靠转义从来都无法彻底防住 XSS

Content Security Policy 的构想最早可追溯到 2004 年前后 Robert Hansen 提出的想法,随后从 2008 年左右开始,Mozilla 工程师 Brandon Sterne 主导将其整理成正式规范,最终在 2012 年形成了 W3C 的第一份候选推荐标准(Level 1)。当时跨站脚本攻击(XSS)是网络安全领域最紧迫的问题之一,人们逐渐意识到,仅依赖「开发者认真转义每一处输出」这种做法并不足以构成稳固的防线。CSP 正是作为一种纵深防御机制被设计出来,让浏览器本身来强制限制脚本的合法来源。

CSP Level 2 引入了基于 nonce 和 hash 的内联脚本许可机制,使网站无需依赖 'unsafe-inline' 也能允许特定的内联代码执行。随后 Level 3 又新增了 'strict-dynamic',可以自动信任由已受信脚本动态加载的子脚本,大幅降低了大型网站维护基于主机名白名单的成本。

Google 持续在其自身的大规模服务中推行基于 nonce 的严格 CSP,并据此发布研究成果指出:基于主机名的白名单方式经常可以被绕过,而基于 nonce 或 hash 的策略在实践中有效得多。这一结论目前已被广泛引用为 CSP 的最佳实践,也说明真正关键的设计决策不只是「禁止哪些取值」,而是「从一开始就该基于哪种许可策略来构建」。

→ 查看全部趣味知识