客户端(由第三方开发)正在发送带有类似标头的请求foo.meta-digest
(请注意标头名称中的“点”)。我的 nginx 反向代理正在从请求中删除这些标头,即使我添加了ignore_invalid_headers off;
(请参阅http://nginx.org/r/ignore_invalid_headers)到此server { ... }
虚拟主机的块:
upstream backend {
keepalive 128;
keepalive_requests 1000;
keepalive_timeout 120s;
server 127.0.0.1:32000 max_fails=0 fail_timeout=10;
}
server {
listen 443 ssl http2;
server_name foo.com;
root /var/www/empty;
ssl_certificate /etc/nginx/certs/foo.com.crt;
ssl_certificate_key /etc/nginx/certs/foo.com.key;
ignore_invalid_headers off;
location / {
proxy_pass http://backend;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
}
}
除了这个特定的客户端之外,我无法使用任何其他客户端重现此问题,并且我无法访问该客户端的源代码,它是专有软件。
如果我使用或任何其他 Web 客户端发送相同的请求curl
,则所有标头(包括名称中带有“点”的标头)都会按应有的方式传递到后端。
我甚至尝试对 nginx 主机进行 mitm 攻击,并拦截来自客户端的网络流量。客户端肯定foo.meta-digest
按预期发送了标头。不知何故,nginx 正在过滤标头,但仅针对此特定客户端。
我还能做什么来调试这个问题?
答案1
刚刚遇到了类似的问题,我只需将其添加ignore_invalid_headers off
到默认服务器即可解决
在我的案例中,客户做了两件奇怪(且不好)的事情:
- 它使用 TLSv1.2 进行连接,但是没有使用信噪比扩展名。
客户端使用它来(以明文形式)提供它所连接的域名,以便服务器能够为正确的虚拟主机使用正确的证书。
如果没有这个,客户端将始终获得默认虚拟主机的证书。...
客户端已将其固定,因此即使它对于域无效,它也会被接受。
请注意,这只会影响您从服务器获得的 TLS 证书!理论上(请参阅后面的第 2 点),nginx 仍将使用标Host:
头来确定哪个是正确的 vhost,以及要使用哪个 conf。
请注意,除非您将证书固定在客户端应用程序中,并且除非您确定证书,否则这样做非常不安全。您将面临 MITM 攻击。
此外,SNI 是在 12 年前开发的,对于虚拟托管来说是必不可少的。
- Nginx 将使用
Host:
Header 来了解要应用哪个 vhost 配置。
正如您所猜到的,因为我告诉过您在默认服务器中添加ignore_invalid_headers
,所以这在特殊情况下不起作用:
RFC7230,第 5.4 节说Host
标题应该是您发送的第一件事。
就我的情况而言(可能您也是这样),情况并非如此。因此,Headers
之前的标头Host
会按照默认服务器配置进行解析,然后 nginx 会找到Host
并切换到正确的 vhost。
奇怪,几乎不符合标准,绝对是不好的做法,但从技术上来说并没有错。
希望能帮助到你