根本不能做本地硬防御,因为file://协议下CSP的<meta>标签完全不生效,浏览器不解析;Chrome 124+已移除对'script-src unsafe-inline'的支持,Safari 16.4前会静默丢弃含nonce或sha256的策略。

为什么根本不能做本地硬防御
直接说结论:<meta http-equiv="Content-Security-Policy">在本地开发或file://协议下完全不生效——浏览器压根不解析它,连警告都不报。这不是配置问题,是协议级限制。
常见错误现象:你加了content="script-src 'self'",但<script>alert(1)</script>照常弹窗;或者用http-server起服务后看似生效,其实只是因为服务端没发响应头才“侥幸运行”,一上真实 Nginx 就立刻失效。
-
file://协议下,所有 CSP(无论<meta>还是响应头)全部关闭 - Chrome 124+ 已移除对
script-src 'unsafe-inline'在<meta>中的支持,写了等于白写 - Safari 16.4 之前版本会静默丢弃含
nonce-或sha256-的整条策略,连调试线索都没有
哪些场景下可能“看起来”有效
只有两个脆弱前提同时满足时,<meta>才可能触发基础拦截:服务端**完全没发**任何Content-Security-Policy响应头,且页面用http://localhost(非file://)打开。
但这不是可靠防御,而是临时调试假象:
立即学习“前端免费学习笔记(深入)”;
- Webpack Dev Server、Vite 默认不发 CSP 头,所以
<meta>能拦住最简单的<script>alert(1)</script> - 一旦你在 Nginx 加了
add_header Content-Security-Policy ""(哪怕值为空),<meta>立刻被忽略 - 它无法覆盖 iframe、Web Worker、fetch 子请求等上下文,攻击者可绕过主文档直接注入
真正该做的本地验证方式
别折腾<meta>,用Content-Security-Policy-Report-Only响应头 + report-uri观察实际行为。本地开发时,在 Nginx 或 Express 中临时加:
add_header Content-Security-Policy-Report-Only "default-src 'none'; script-src 'self'; report-uri /csp-report";
然后在控制台看Security Policy Violation日志,确认哪些脚本被拦、为什么被拦。这样既不阻断功能,又能暴露真实风险点。
- 必须用
report-uri或report-to,<meta>不支持这两个指令 -
default-src 'none'是关键起点,它让所有未声明的资源类型默认拒绝,避免漏配 - 本地验证通过后,再把
-Report-Only去掉,切为强制模式
容易被忽略的物理约束
就算你坚持要用<meta>做临时测试,也得卡死三条规则,错一条就全盘失效:
- 必须是 HTML 中**第一个**
<meta>标签,早于<title>、<meta charset>、<link> -
content属性值不能换行、不能首尾空格、不能含未转义引号(如content="script-src 'self' https://cdn.com"合法,content="script-src 'self' \nhttps://cdn.com"整条失效) - 整个页面只允许一个
<meta http-equiv="Content-Security-Policy">;Webpack 插件自动生成 + 手动添加容易重复,浏览器只认第一个
这些不是建议,是浏览器强制执行的解析规则。真要上线,必须放弃<meta>,走服务端响应头——否则所谓“本地防御”只是给自己制造虚假安全感。



















