直接在 nginx 中配置 csp 是防范 xss 最有效、最现代的服务端手段,需先用 content-security-policy-report-only 模式观察 3–7 天违规报告,再逐步收紧策略;禁用 'unsafe-inline' 和 'unsafe-eval',改用动态 nonce 或 sha256 hash;所有 add_header 必须加 always 参数,统一在 server 或 http 块配置,并关闭后端同名头以避免冲突。

直接在 Nginx 中配置 Content-Security-Policy(CSP)是防范 XSS 最有效、最现代的服务端手段,但它不是“加一行就完事”的简单操作。关键在于策略合理、覆盖全面、避免冲突,并配合后端协同落地。
用 report-only 模式起步,先观察再收紧
上线 CSP 前不要直接启用阻断模式。先用 Content-Security-Policy-Report-Only 收集真实违规行为:
- 在 server 或 http 块中添加:
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'; connect-src 'self' https:; report-uri /csp-report;" always; - 部署后持续观察 3–7 天的违规报告,识别哪些内联脚本、CDN、动态 eval 是业务必需的
- 确认无误后再将
Content-Security-Policy-Report-Only替换为Content-Security-Policy,并逐步移除'unsafe-inline'和'unsafe-eval'
禁用高危指令,强制使用 nonce 或 hash
允许 'unsafe-inline' 或 'unsafe-eval' 会让 CSP 大幅失效。必须改用更安全的加载方式:
- 对每个页面响应生成唯一 nonce(如
nonce="R1nd0mB4s364=="),后端注入到<script nonce="R1nd0mB4s364=="></script>标签中 - Nginx 同步注入该值:
add_header Content-Security-Policy "script-src 'self' 'nonce-R1nd0mB4s364==' https://cdn.example.com; default-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self';" always; - 若无法动态注入 nonce,可用 SHA256 hash 替代:对内联脚本内容计算 hash,写入
script-src 'sha256-xxx...'
确保所有响应都携带 CSP,避免防护盲区
CSP 必须作用于所有 HTTP 响应,包括错误页、重定向、静态资源——否则攻击者可绕过:
- 所有
add_header都要加always参数,例如:add_header Content-Security-Policy "..." always; - 避免在多个 location 块中重复定义 CSP,防止覆盖;推荐统一在 http 或 server 级别设置
- 检查后端是否也输出 CSP 头,如有则必须关闭,只由 Nginx 单一源头管理,避免冲突或策略被覆盖
搭配基础安全头构成完整防线
CSP 是主力,但不能单打独斗。以下响应头需同步配置,并全部加上 always:
-
X-Content-Type-Options: nosniff—— 防止浏览器 MIME 嗅探导致文本文件被当作脚本执行 -
X-Frame-Options: SAMEORIGIN或DENY—— 防点击劫持(旧浏览器兼容用) -
Referrer-Policy: no-referrer-when-downgrade—— 控制 Referer 泄露范围 - 明确弃用
X-XSS-Protection—— 主流浏览器自 2023 年起已完全忽略,配置无效还可能误导运维











