Content-Security-Policy 必须通过 HTTP 响应头设置才生效,<meta> 标签在绝大多数真实部署场景下无效,因其不支持 nonce/hash/'unsafe-inline'、report-to 等关键机制,且易被服务端响应头覆盖、CDN/代理忽略,解析滞后导致内联脚本已执行。

Content-Security-Policy 必须通过 HTTP 响应头设置才生效,<meta> 标签在绝大多数真实部署场景下无效。
为什么 <meta http-equiv="Content-Security-Policy"> 大概率不工作
浏览器对 <meta> 的 CSP 支持有严格限制:不支持 script-src 中的 nonce、hash、'unsafe-inline' 等关键机制;不支持 report-to;且在 document.write、动态插入 script 等场景下策略可能被跳过。更关键的是,很多现代框架(如 React/Vue SSR)、CDN 缓存、反向代理(如 Nginx)会忽略或覆盖 meta 标签中的策略。
常见错误现象:本地用 VS Code Live Server 或双击打开 HTML 时,控制台看到 CSP 报错但脚本仍执行;上线后审计工具报“CSP 未启用”或“策略被绕过”。
- 开发调试时可用
python3 -m http.server或vite preview启服务,再检查响应头 - 用
curl -I https://yoursite.com/确认返回头中存在content-security-policy - Chrome DevTools → Network → HTML 请求 → Response Headers → 查找
content-security-policy字段
script-src 里漏掉 'unsafe-inline' 却没报错?那是假安全
只写 script-src 'self' https://cdn.example.com,看起来拦住了外链恶意脚本,但所有内联脚本(<script>alert(1)</script>)、内联事件(<button onclick="doX()">)、eval()、setTimeout("...") 全部放行——攻击者根本不需要外链就能注入。
立即学习“前端免费学习笔记(深入)”;
真正起效的前提是:显式排除 'unsafe-inline' 和 'unsafe-eval',再用 nonce 或 hash 白名单化必需的内联代码。
- 用
nonce:服务端每次响应生成新随机值(如abc123),HTML 中写<script nonce="abc123">...</script>,响应头配script-src 'nonce-abc123' - 用
hash:对脚本内容(不含<script>标签)做 SHA256,得sha256-BzLdO9X...,响应头写script-src 'sha256-BzLdO9X...' - 硬编码
nonce值、复用同一值、或把hash用于拼接字符串的动态脚本,都会导致脚本白屏
上线前必须显式声明的 4 个冷门但高危指令
default-src 'self' 不等于万事大吉。CSP 对 base-uri、form-action、frame-ancestors、object-src 默认宽松,不设就等于留后门。
-
base-uri 'self':防止攻击者用<base href="http://evil.com">劫持所有相对路径资源(图片、CSS、AJAX) -
form-action 'self':阻止表单提交到第三方,是防 CSRF 的最后一道防线 -
frame-ancestors 'none'或'self':防点击劫持(clickjacking),比旧的X-Frame-Options更可靠 -
object-src 'none':禁用 Flash/Java 插件,避免利用插件加载恶意 payload
开发期怎么试才不会炸掉整个页面
直接上 Content-Security-Policy blocking 模式,大概率导致 JS/CSS 加载失败、功能瘫痪。必须先走 Content-Security-Policy-Report-Only + report-to 路径。
注意:report-uri 已废弃,必须用 report-to 配合独立的 Report-To 响应头,否则报告发不出去。
- 响应头示例:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-to csp-endpoint+Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://yoursite.com/csp-report"}]} - 浏览器会照常加载资源,但把所有违规行为(被拦的脚本、样式、iframe)以 JSON 发到你指定接口
- 重点看报告里的
violated-directive和blocked-uri,它们直接告诉你哪条规则挡了什么、该加白名单还是抽成外部文件
最易被忽略的是:iframe 里加载的 HTML、fetch 返回的 HTML 片段、Worker 脚本,它们各自需要独立的 CSP 响应头——主页面加了不等于子资源也受保护。



















