CSP响应头必须由服务端通过HTTP响应头发送,<meta>标签在生产环境基本无效;本地file://协议下CSP全面关闭,Chrome 124+还限制其关键指令支持。

Content-Security-Policy响应头必须由服务端发,基本无效
浏览器只认 HTTP 响应头里的 Content-Security-Policy,<meta http-equiv="Content-Security-Policy"> 在绝大多数生产环境里被忽略——只要服务端返回了任意 CSP 头(哪怕语法错误), 就彻底失效。本地用 file:// 协议打开 HTML 时,CSP 全面关闭;Chrome 124+ 还限制 对 script-src 等关键指令的支持。
实操建议:
- 确认是否生效:Chrome DevTools → Network → 找到 HTML 请求 → Response Headers → 查看是否有
content-security-policy(全小写) - Nginx 示例:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; ...";,注意双引号包裹整条策略,内部单引号用于源关键字 - 开发期若无后端,可用
http-server -p 8080 --cors --headers headers.json模拟响应头,headers.json中写入 CSP 字段
script-src 'self' 不拦内联脚本,必须配合 nonce 或 hash
只写 script-src 'self' 等于没设 CSP:所有 <script>alert(1)</script>、onclick="doSomething()"、eval() 都照常执行。真正起效的前提是:不写 'unsafe-inline'、不写 'unsafe-eval',再显式授权合法内联脚本。
选 nonce 还是 hash?
立即学习“前端免费学习笔记(深入)”;
-
nonce:服务端每次响应生成新随机值(如abc123),HTML 中写<script nonce="abc123">,响应头配script-src 'nonce-abc123';硬编码或复用 nonce 值等于形同虚设 -
hash:对脚本内容(不含<script>标签)做 SHA256 摘要,如sha256-BzLdO9X,写进策略;适合构建时确定的静态内联脚本,动态拼接的无法预计算 - 两者可共存,但浏览器只匹配其一;没匹配上的脚本仍被拦截
default-src 'none' 是起点,漏配指令会导致资源静默失败
设 default-src 'none' 后,所有资源类型(图片、样式、字体、连接等)默认被禁,必须显式声明才能加载。否则资源不报错,只静默 404,控制台仅显示 CSP violation,不提示缺哪条指令。
常见漏配项:
-
img-src没加data:→ base64 图片炸掉 -
connect-src没覆盖 API 域名 →fetch()或 WebSocket 连接失败 -
font-src漏了 CDN → 字体图标不显示 -
style-src没给'unsafe-inline'或 hash → 内联<style>或框架注入样式失效
media-src、base-uri、form-action 这些指令不显式配就等于留后门
media-src 专管 <video>/<audio> 的 src、poster、WebVTT 字幕等,未设置则回退到 default-src,容易遗漏;base-uri、form-action、frame-ancestors、object-src 默认宽松,不显式配置就是攻击入口。
必须显式写:
-
base-uri 'self':防恶意<base href="http://attacker.com">劫持所有相对 URL -
form-action 'self':阻止表单提交到第三方,防 CSRF 和数据外泄 -
frame-ancestors 'none'或'self':防点击劫持(被嵌入钓鱼页) -
object-src 'none':禁 Flash/Java 插件,老漏洞温床 -
media-src 'self' https://cdn.example.com:HLS 分片、字幕 .vtt 文件都受它约束,别依赖'self'覆盖全部
上线前最易被忽略的点:富文本渲染、模板引擎插值、动态 innerHTML 注入的脚本,不会继承父页面 CSP,必须单独验证是否匹配策略;iframe、worker、fetch 返回的 HTML 片段也得各自带头,否则策略失效。



















