CSP 头部验证工具

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

检视 CSP 标头的内容

Content-Security-Policy 是一条以分号分隔的长串,单凭肉眼顺下来,危险之处最易被漏过。本工具会把您贴入的值拆成指令与来源,把危险的设定、缺失的声明与拼写之误一一揪出,并把每条指令究竟准许了什么摊开来看。

**其中最棘手的,莫过于指令名的拼写之误。** 浏览器对不认识的指令一概默默忽略,于是把 `script-src` 写成 `scipt-src`,**既不报错,那一段策略也就这么一直什么都不做。** 同样容易被忽略的是 `default-src` 的缺失:少了它,凡您未逐一写明的指令便不受任何限制,防线上就此裂开一道口子。而把 `unsafe-inline` 放进 script-src,**几乎等于把「阻断内联脚本」这一采用 CSP 的首要目的一笔勾销。**

使用方法

  1. 贴入 CSP 标头的值 把形如 `default-src 'self'; script-src ...` 的字符串照原样放进去。
  2. 先试一试样例 好例与坏例都已备好,动手之前便可看出判定的分别。
  3. 阅读所提出的各点 **`unsafe-inline`、缺失的 `default-src` 与拼写之误都会被点名。**
  4. 查看每条指令准许的来源 准许从何处加载,一览便知。

用好本工具的小技巧

  • 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

在策略还离生产环境甚远时,便可确认它是否照您的本意行事。

盘点既有的策略

**日积月累长起来的策略,往往还留着早已无人使用的域名的许可。**

由仅报告转为强制

在 `Content-Security-Policy-Report-Only` 下试过的值,可在正式强制之前先行检视。

辅助代码评审

把改动后的策略贴上,确认它并未因此变弱。

CSP 的术语

指令
如 `script-src` 或 `img-src` 之类的条目,**它言明某一类资源可从何处加载。**
default-src
凡未逐一写明的指令所回落到的默认值。**略去它,凡您未写明的类别便不受限制。**
'self'
只准许来自同源加载的来源表达式。
'unsafe-inline'
准许直接写在 HTML 里的脚本与样式的来源表达式。**它几乎断送了对 XSS 的防御,宜改用 nonce 或 hash。**
nonce
把一个一次性的随机值同时写进脚本标签与策略,使二者相对应的办法。这是安全地准许内联代码的途径。
frame-ancestors
言明何人可将您的站点嵌入框架的指令。**它是 X-Frame-Options 的后继者。**

常见问题

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 的最佳实践,也说明真正关键的设计决策不只是「禁止哪些取值」,而是「从一开始就该基于哪种许可策略来构建」。