前进笔记

针对 nginx 中 add_header 指令的层级继承所引起的问题的分析与解决

问题

做测试的时候有个偶然发现

curl 显示的头部信息竟然与 nginx 中的配置不一样
又去看了一眼 nginx 配置参数,我并不认为有什么错误的地方。

配置文件

全局配置 nginx.conf

http {
......
# 禁止被嵌入框架
add_header X-Frame-Options DENY;
# 防止在IE9、Chrome和Safari中的MIME类型混淆攻击
add_header X-Content-Type-Options nosniff;
# 防止 XSS 跨站攻击
add_header  X-Xss-Protection "1; mode=block";
......
include /etc/nginx/conf.d/*.conf;
}

子域配置 blog.conf

server{
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
}

分析

显然只有 server 块中的 add_header 被实现,http 块中添加的响应头并没有出现,马上对另外几个子域测试了一下,并没有出现这种情况。

第一反应觉得可能是 http 块不支持 add_header ,但仔细想想马上就否定了这个可能,首先不说 http 块不支持添加响应头不合理,即便不支持那也应该会当场报错才对。

CDN 当然也可以排除,因为我根本没用 CDN ,而且 CDN 一般也不会做这种事。

有意思的是,http 访问也能正常出现响应头,我配置了全站 https 因此 http 访问是单独在一个 server 进行重定向的。

而值得注意的是,先前在还未实现对 http(s) 访问的全局配置时,为了实现 HSTS Preload 标准,我将 HSTS 响应头写进了 server 块中,并且只写到了主域的配置中,之后一直没改过来。

而 http 块中的 add_header 在申请 HSTS 之前就已经加入也一直正常。

那么问题只能出在不同层级的指令继承上

解决

试着编辑子域配置,先将配置中的 add_header 内容注释掉,再执行 nginx -s reload ,查询响应头信息,这时 http 块中的响应头果然正常显示。

原因

这是在 解决HSTS Warning: Unnecessary HSTS header over HTTP 时引发的错误

事实上在 nginx.orgModule ngx_http_headers_module 中,有这样一段内容

There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.
可能会存在多个add_header指令。当且仅当当前级别没有定义add_header指令时,这些指令才从上一级继承。

也就是说,我在 server 块中添加了 HSTS 响应头,就把上一层级 http 中的 add_header 信息就被丢弃了。而我在其他子域中未加入 HSTS 响应头,所以才不会出现这一情况。

这么做的优点大概就是便于控制响应头添加位置吧,但有时候确实有些麻烦,如果有多个子层级使用同一响应头信息,又要额外配置不同 header 时就不得不只能重复写同一指令。

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »