安全头检测失败,CSP配置到底该怎么写才对?
我在项目里加了 Content-Security-Policy 头,但用安全扫描工具一测还是报“缺少安全头”或者“CSP 配置不安全”。本地开发时用的是 nginx,已经尝试在配置里加了 add_header Content-Security-Policy "default-src 'self'";,但好像没生效?
这是我的 nginx 配置片段:
location / {
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline';";
try_files $uri $uri/ /index.html;
}
是不是哪里写错了?为什么检测工具还是说 CSP 有问题?
add_header行为上。你写在location /里的add_header,在配合try_files使用时,只有当请求最终命中了静态文件(比如$uri存在)时,这些头才会被加上;如果请求被重写到/index.html(比如前端路由跳转),nginx 就不会继承外层的add_header,导致 CSP 头根本没发出去——这就是为什么扫描工具检测失败。最简单的修复方式是把 CSP 头提到
server块里,或者用always参数强制添加:注意我顺便把
'unsafe-inline'去掉了,因为现在主流扫描工具(比如 Mozilla Observatory、securityheaders.com)会把 inline script 视为高风险配置——除非你真有历史包袱必须用,否则建议先去掉它,后面再通过 nonce 或 hash 细粒度控制。如果还是不生效,记得检查响应头是不是被反代(比如 nginx 后面还挂了 Apache 或 Cloudflare)给覆盖了,这种情况得在最外层统一加头。
首先,
add_header在 nginx 里有个坑:如果某个 location 块里用了try_files,那这个 location 里的add_header只有在返回的状态码是 200、201、204、206、301、302、303、304、307 或 308 时才会生效。但更关键的是,nginx 的add_header是覆盖式的——如果上级配置(比如 server 块)或者默认模块(比如error_page)也加了 header,可能会覆盖你这个,或者干脆不生效。你检测工具报“缺少安全头”,大概率是这个 CSP 头根本没发出去。
先确认下:用浏览器 F12 看响应头里到底有没有
Content-Security-Policy这个字段。如果没看到,那说明 nginx 根本没加进去。通用的做法是把
add_header放到server块里,别放location里,避免被try_files干扰。比如:注意几个点:
- 所有
add_header都加了always,这是关键,否则 nginx 在某些响应(比如 4xx、5xx)里根本不加头。- 你原来的 CSP 里没写
style-src,现代项目基本都得加'unsafe-inline'才能跑起来(除非你用 hash 或 nonce),不然样式全挂。-
img-src 'self' data:是为了支持 base64 图片,很多地方会用。-
frame-ancestors 'none'是 CSP 的防点击劫持,比X-Frame-Options DENY更现代,但你留着X-Frame-Options也行,兼容性更好。另外,如果你用了 nginx 的
error_page自定义错误页,记得error_page的 location 里也得加 CSP,或者直接在 server 块统一加,别漏了。最后,改完配置别忘了
nginx -s reload,有时候你以为 reload 了但其实没生效(比如配置文件没写对),可以用nginx -t先检查语法。如果还是没生效,贴下完整 server 块配置,我帮你看看是不是被其他模块干掉了。