Nginx 中仅用 add_header 配置 CSP 不可靠,因其不继承父级、覆盖子块配置、不作用于重定向/错误页/静态资源,且易与后端冲突;应统一由 Nginx 管理,顶层设置、动态策略用 map,API 路径单独限制,渐进启用 report-only 模式,nonce 需前后端协同生成并注入,部署后须验证 header 存在性、大小写、中间件覆盖及语法规范。

直接在 Nginx 中用 add_header 设置 Content-Security-Policy(CSP) 是防范 XSS 最有效的服务端手段之一,但配置不当反而会导致页面功能异常或策略完全失效。
为什么不能只靠 add_header?关键在于响应头覆盖与缺失
Nginx 的 add_header 指令不会继承父级作用域的 header,且在 location 块中重复定义会覆盖上级配置;更严重的是:它不向 301/302 重定向响应、错误页(如 404、500)或静态文件(如 JS/CSS)自动添加 CSP。若后端应用本身也输出 CSP 头,还可能产生冲突。
- 确保 CSP 只由 Nginx 统一注入,后端代码中移除所有
Content-Security-Policy相关 header 输出 - 在
http或server块顶层设置,避免被子 location 覆盖;如需差异化策略,用map指令动态生成值 - 对
/api/等接口路径,可单独用add_header关闭脚本执行(如script-src 'none'),增强 API 安全边界
一个实用、渐进式上线的 CSP 配置示例
不建议一步到位启用 default-src 'none'。从报告模式起步,收集真实违规行为后再收紧:
- 先启用
Content-Security-Policy-Report-Only,搭配report-uri或report-to收集浏览器上报 - 典型过渡配置(放在 server 块中):
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; font-src 'self'; connect-src 'self' https:; report-uri /csp-report;" always;
- 观察 3–7 天报告,识别合法内联脚本、外部 CDN、动态 eval 使用点,再逐步移除
'unsafe-inline'和'unsafe-eval',改用nonce或hash
配合 nonce 实现严格 script-src 的关键细节
仅靠 add_header 无法生成动态 nonce——Nginx 本身无运行时上下文。必须前后端协同:
- 后端渲染 HTML 时,为每个请求生成唯一 base64 编码 nonce(如
nonce="Ea4aXpL9rZ"),并写入 script 标签:<script nonce="Ea4aXpL9rZ">...</script> - Nginx 在响应头中同步注入该 nonce:
add_header Content-Security-Policy "script-src 'self' 'nonce-Ea4aXpL9rZ'";
⚠️ 注意:实际需由后端把 nonce 值注入 Nginx 变量(如通过sub_filter替换占位符,或用 OpenResty 的 Lua 模块动态 set header) - 若使用
hash,需预先计算脚本内容 SHA256 并写入策略,适用于构建时确定的静态资源
绕过陷阱:常见失效原因与验证方法
CSP 生效与否极易被忽略。部署后务必验证:
- 打开 Chrome DevTools → Network → 刷新页面 → 查看任意 HTML 响应头,确认
Content-Security-Policy存在且拼写准确(注意不是content-security-policy小写) - 在 Console 中手动触发违规(如
eval('1+1')),观察是否出现[Report Only] Refused to evaluate...日志 - 检查是否被其他中间件覆盖:CDN(如 Cloudflare)、负载均衡器、反向代理层可能删除或重写 header;可在 Nginx access log 中加
$sent_http_content_security_policy字段确认发出值 - 避免在 CSP 中混用单引号和双引号导致解析失败;所有源值必须用单引号包裹,关键字(如
self、none)不加引号











