Opened 6 years ago
Last modified 6 years ago
#1724 new enhancement
Nginx doesn't sanitize and is inconsistent with multiple, repeated input headers
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | minor | Milestone: | |
Component: | nginx-core | Version: | 1.15.x |
Keywords: | http header | Cc: | |
uname -a: | Linux 186b85fdedd6 4.20.6-100.fc28.x86_64 #1 SMP Thu Jan 31 15:51:26 UTC 2019 x86_64 Linux | ||
nginx -V: |
nginx version: nginx/1.15.8
built by gcc 8.2.0 (Alpine 8.2.0) built with OpenSSL 1.1.1a 20 Nov 2018 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-threads --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-stream_geoip_module=dynamic --with-http_slice_module --with-mail --with-mail_ssl_module --with-compat --with-file-aio --with-http_v2_module |
Description
Ola,
I understand this is not supported by HTTP specification, but nginx behavior on multiple, repeated headers is inconsistent, possibly leading to errors and attack vectors.
If a client sends a repeated HTTP header, internally nginx uses the first incoming header, but forwards the last one to the backend. For example, if a client sends a request like this:
GET / HTTP/1.1 Host: myserver.com Host: notmyserver.com
The myserver.com will be accepted and parsed as the $server_name, but backend servers (tested with php-fpm on fgci_pass) actually receive notmyserver.com.
Still, if I manually set it:
fastcgi_param HOST_NAME $host; # or fastcgi_param HOST_NAME $http_host;
The correct host (first one) will be sent to backend.
The same odd behavior is found on other repeated http headers (like content-length), possibly leading to other attack vectors.
Tested on docker nginx-alpine:latest
Cheers,
Guilherme Capilé
Change History (2)
comment:1 by , 6 years ago
Type: | defect → enhancement |
---|
comment:2 by , 6 years ago
For the record, multiple Host
headers are allowed since nginx 0.7.0 (revision b9de93d804ea):
*) Change: now nginx allows several "Host" request header line.
These were allowed as a workaround for broken clients, specifically some Motorola phones, which used to sent two Host
headers, with localhost
in the second one (see here, in Russian).
Internally, nginx will always use the first Host header field received (much like it will prefer host from the request line, if available). When passing HTTP headers to a FastCGI application it will, however, pass all the headers it received. It is up to the application to handle these headers.
To improve things, we may consider rejecting requests with duplicate
Host
headers. This is also explicitly required by RFC 7230:Also, we probably also need to reject requests with Host header which does not match host from the request line, since without such a check it will be trivial to provide arbitrary HTTP_HOST to an application anyway.
As for other repeated HTTP headers, this actually depends on the header. In particular, duplicate Content-Length headers are explicitly rejected.