加了 CSP 之后页面为什么白屏了?

3 个讲解板块 · 关联 3 款站内工具 · 内容最后核对 2026-10-09

策略按你的要求执行了:内联脚本和样式不再被允许执行。

直接答案

因为绝大多数站点的首屏脚本是内联写在 HTML 里的,而严格的 script-src 只允许从指定来源加载外部脚本文件。浏览器给出的报错会明确列出三个出口:unsafe-inline 关键字、一个哈希、或者一个 nonce。这三个选项按「损害防护的程度」降序排列——最省事的那个恰好也是最不该用的。

稳妥的上线顺序是两段式:先发只报不拦的报告模式(header 名换成带 Report-Only 的那个,策略内容完全一样),收集一两周真实流量的违规报告,把忘掉的合法来源(CDN、分析、错误监控)补进白名单,再换成强制头。纯静态页面还有个额外限制:nonce 必须每次响应都不同,被 CDN 缓存的静态页做不到,只能用哈希。

安全加固做了一半,页面变成一片空白,控制台里刷出一片红色报错。这一刻很容易想把刚加的头去掉当作没发生——但报错本身恰好说明策略生效了,问题只在于你把自家脚本也一起拦住了。

把三个出口和上线顺序理清楚,这件事就不难,只是不能一次到位。

1三个出口与各自的代价

报错信息里会把这三条路都列出来,选哪条决定了策略还剩多少价值。

方案怎么写代价
unsafe-inlinescript-src 里加该关键字等于关掉 CSP 对脚本注入的主要防护;有 nonce 或哈希时浏览器会忽略它
哈希对固定内容算 sha256 写进策略内容一个字节都不能变,含空白;只适合构建期固定的内联脚本
nonce每次响应生成新随机值,同时写进响应头与脚本标签必须服务端渲染逐次生成;纯静态页与 CDN 缓存的页面用不了

先看清楚是谁被拦了:报错里的区块名指向具体位置,多数时候不是主脚本,而是某个分析代码、客服组件或 CDN 注入的加载器。

2上线顺序:先报后备

四步走,每一步都可回退。

第一步:换成报告模式
头字段名加 Report-Only,策略内容一个字都不改。此时什么都不会被拦,只会产生违规报告。
第二步:收集一到两周
覆盖真实流量与各端用户,包括移动端、不同地区、装了浏览器扩展的人。
第三步:区分两类报告
一类是你忘了加的真实依赖,需要补白名单;另一类是浏览器扩展注入的脚本,属于噪音,可以直接过滤掉。
第四步:换回强制头并保留上报
强制之后仍然保留上报端点,新功能引入的新来源会第一时间暴露出来。

3几个高频踩坑

这些坑几乎每个站点都会遇到一次。

第三方脚本二次加载
分析平台、标签管理器会从没写进白名单的域名再拉脚本,报告里才看得到。
CDN 的自动优化功能
有些 CDN 会注入内联脚本做加载优化,需要在 CDN 侧关掉,而不是给页面放开内联权限。
第三方组件污染主页面
客服、评论、地图这类组件最好装进自带宽松策略的 iframe,别为了它们放宽整个页面。
把评分当成目标
一个带 unsafe-inline 的高分,安全性还不如一个用严格 nonce 的中等分。

相关疑问

为什么加 unsafe-inline 之后就没效果了?

因为 CSP 的主要价值就是阻止注入的脚本执行,而内联脚本正是最常见的注入落点。放开它,策略看起来配置完整,实际上对脚本注入几乎没有防护力。另外要注意:当策略里同时存在 nonce 或哈希时,浏览器会直接忽略 unsafe-inline。

nonce 和哈希该怎么选?

内容是固定的(构建期就定死的)用哈希,省服务端逻辑;内容是每次请求动态生成的用 nonce。纯静态站点、或者页面被 CDN 与浏览器缓存复用的,只能用哈希,因为 nonce 一旦被缓存就固定在页面里,防护意义消失。

上线 CSP 一般要观察多久?

常见做法是报告模式先跑一到两周,覆盖完整的周中与周末流量。判断可以切换的信号是:违规报告量降到以浏览器扩展噪音为主,剩下的是你明确评估过并接受的风险。

CSP 能彻底防住 XSS 吗?

不能。它是纵深防护的一层:让注入的代码更难执行,降低被利用的概率与影响面,但不消除漏洞本身。输入校验、输出转义、服务端鉴权仍然是基础。

内容标识:本页内容由人工智能辅助生成,并经人工核对与编辑。详见 人工智能生成内容标识说明。
内容说明:本页针对具体使用问题作答,方法步骤与数值由本站自行整理与复算,事实性内容以对应官方规范与文档为准。内容最后核对日期:2026-10-09。若发现错误,欢迎通过页脚反馈入口告知。