安全头检测失败,CSP配置到底该怎么写才对?

公孙玉翠 阅读 18

我在项目里加了 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 有问题?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
极客耘郗
问题应该出在 nginx 的 add_header 行为上。你写在 location / 里的 add_header,在配合 try_files 使用时,只有当请求最终命中了静态文件(比如 $uri 存在)时,这些头才会被加上;如果请求被重写到 /index.html(比如前端路由跳转),nginx 就不会继承外层的 add_header,导致 CSP 头根本没发出去——这就是为什么扫描工具检测失败。

最简单的修复方式是把 CSP 头提到 server 块里,或者用 always 参数强制添加:

location / {
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self';" always;
try_files $uri $uri/ /index.html;
}


注意我顺便把 'unsafe-inline' 去掉了,因为现在主流扫描工具(比如 Mozilla Observatory、securityheaders.com)会把 inline script 视为高风险配置——除非你真有历史包袱必须用,否则建议先去掉它,后面再通过 nonce 或 hash 细粒度控制。

如果还是不生效,记得检查响应头是不是被反代(比如 nginx 后面还挂了 Apache 或 Cloudflare)给覆盖了,这种情况得在最外层统一加头。
点赞
2026-02-27 18:05
Dev · 新红
你这个配置看起来没大问题,但有几个常见坑,我来帮你捋一捋。

首先,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 干扰。比如:

server {
listen 80;
server_name your-domain.com;

add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;

location / {
try_files $uri $uri/ /index.html;
}
}


注意几个点:
- 所有 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 块配置,我帮你看看是不是被其他模块干掉了。
点赞 2
2026-02-26 14:22