an attacker could exploit this ambiguity to bypass security restrictions configured in NGINX (of have other security impacts).
Example:
GET http://foo/ HTTP/1.1 <- Used for virtual host routing User-Agent: UA Host: bar <- Used for $httphost
Debian's proxyparam file used to use $httphost:
proxysetheader Host $httphost;
This has been fixed as part of Debian bug #1126960 [1].
In this case, "foo" is used for virtual host routing but the request is forwarded as:
GET / HTTP/1.1 User-Agent: UA Host: bar X-Real-IP: ... X-Forwarded-For: ... X-Forwarded-Proto: ...
If the backend application actually makes use of the Host value, this might have a security impact. For example,
if the backend application uses the Host value for tenant dispatching; logging, etc),
then this might have a security impact.
Example NGINX configuration:
server { listen 443 ssl; servername tenant1; sslcertificate /etc/nginx/ssl/tenant1.crt; sslcertificatekey /etc/nginx/ssl/tenant1.key; location / { proxypass http://backend; include proxyparams; } } server { listen 443 ssl; servername host2; sslcertificate /etc/nginx/ssl/tenant2.crt; sslcertificatekey /etc/nginx/ssl/tenant2.key; location / { allow 10.0.0.0/8; allow 192.168.0.0/16; allow 127.0.0.1/8; deny all; proxypass http://backend; include proxyparams; } }
In this example, tenant2 is expected to be only available from private IP addresses. However, an attacker could target tenant2 with:
GET http://tenant1/ HTTP/1.1 <- Used for virtual host routing User-Agent: UA Host: tenant2 <- Used for $httphost
Another potential application, would be to send access logs of an attack to the log files of the wrong tenant.
You might be impacted if:
NGINX is directly exposed; you use $httphost (eg. through Debian's proxyparams).
NGINX's position ----------------
NGINX's position is that the bug is to use $http host. NGINX's documentation recommends using $host [2]:
proxysetheader Host $host;
I would claim that NGINX could (should?):
1. either reject host ambiguous requests altogether (because they are attacks right?); 2. or override the HTTP header with the value from the request line.
These behaviors are consistent with what other (open-soruce) HTTP server do:
1. NGINX when using HTTP/2, HA proxy for solution 1; 2. Traefik, Caddy, Apache HTTPD for solution 2.
At the very least, the security impact of using $host vs $httphost should be better documented.
Mitigations -----------
Mitigation 1: always use $host instead of $httphost:
proxysetheader Host $host; proxysetheader X-Forwarded-Host $host;
Mitigation 1b: always use $servername instead of $httphost:
proxysetheader Host $servername; proxysetheader X-Forwarded-Host $servername; proxysetheader Host "www.example.com"; proxysetheader X-Forwarded-Host "www.example.com"; Does not work when using ports: if ($host != $httphost) { return 421 "Ambiguous host"; }
# Since nginx 1.29.3: if ($httphost != "$host$isrequestport$requestport") { return 421 "Ambiguous host"; }
Debian info -----------
Snippet from Debian changelogs:
nginx (1.26.3-3+deb13u4) trixie; urgency=medium d/conf/params: use "$host" instead of "$httphost" requests with a conflicting Host header) backend applications (uwsgi, fastcgi, scgi, proxy) switch to "$host" as a safer, normalized alternative note: this changes behaviour, as "$host" does not preserve the a port number may be affected
New proxyparams file:
# !!! Security workaround !!! # Do not set the Host header as "$httphost". # # "$httphost" is the Host header exactly as supplied by the client. with a different Host header, for example: # # GET https://example.com/ HTTP/1.1 # Host: malformedhost # behaviour. # "$requestport", allowing Host to be constructed as: # $host$isrequestport$requestport # It avoids forwarding an untrusted raw Host header to the backend. # may therefore break or behave differently after this change. proxysetheader Host $host; proxysetheader X-Real-IP $remoteaddr; proxysetheader X-Forwarded-For $proxyaddxforwardedfor; proxysetheader X-Forwarded-Proto $scheme;
[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1126960 [2] https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ Regard,
-- Gabriel Corona
Errata: the subject of the original message is bogus and should instead read,
Host ambiguous requests through NGINX $httphost and Debian's proxyparams
Sorry for that,
-- Gabriel Corona