OWASP ZAP扫描时为什么总报“缺少安全头”?

书生シ雨晨 阅读 7

我用 OWASP ZAP 扫描自己的前端项目,每次都会提示“Missing Security Headers”,比如 X-Content-Type-Options 和 X-Frame-Options。但我已经在 Nginx 里加了这些头啊:

add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";

本地 curl 测试也能看到响应头正常返回,可 ZAP 还是报错,这是为啥?是不是我配置的位置不对?

我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
迷人的玉涵
兄弟,这问题太经典了。ZAP 扫得到但 curl 看得到,基本就是 Nginx add_header 的继承坑。

根本原因:add_header 不会自动往下继承

Nginx 的 add_header 有一个恶心的地方:如果某个 location 块里已经写了任何 add_header,那上级(server 块)的 add_header 就会被完全覆盖,不会合并。

你的配置大概率放在了 server 块,但 ZAP 扫描的请求命中了某个 location(比如 /api/ 或者静态资源的 location),而那个 location 里有其他的 add_header(比如 Cache-Control),导致安全头全没了。

排查方法:

用 curl 扫一下 ZAP 扫描的具体路径,别只扫首页:

curl -I http://你的域名/api/xxx
curl -I http://你的域名/
curl -I http://你的域名/static/xxx.js


看看哪些路径缺安全头。

解决方案:

两种改法,看你项目情况:

第一种,把安全头配到每个 location 里,麻烦但稳妥:

location / {
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
# ... 其他配置
}

location /api/ {
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
# ... api 相关配置
}


第二种,用 include 抽成公共配置,然后每个 location 都引用,更清爽。

还有一点:记得加 always 参数,不然在 4xx/5xx 响应时安全头不会返回,ZAP 扫到错误页面还是会报缺失。

改完reload Nginx,再跑一次 ZAP 看看。
点赞 1
2026-03-12 07:04
极客欣辰
这个问题很常见,典型的 Nginx add_header 继承坑。

你大概率是在 location 块里又加了 add_header,导致之前 server 块里配置的头部被覆盖了。Nginx 的 add_header 不会继承父级的headers,你在一个层级写了新的 add_header,之前配置的全部失效。

检查一下你的配置是不是类似这样:

server {
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";

location / {
add_header X-Frame-Options "SAMEORIGIN"; // 这里一写,server块的两个头全没了
}
}


解决办法很简单,把所有头部统一放在同一个层级配置,或者在 location 块里把需要的头部全部写上。

另外还有一种情况:如果你的配置在 if 条件内部,Nginx 1.7.2 之前的版本 add_header 在 if 里是不生效的。

你可以用 curl -I 看看 ZAP 访问的那个具体 URL 返回的响应头是不是真的都有,或者直接在 ZAP 的响应面板里查看,比 curl 更准——因为有些项目会区分内外网配置。

最直接的排查方法:在 ZAP 里找到那个报错的响应,右键看 Response Headers,确认实际返回的头部到底有没有。
点赞
2026-03-11 11:10