Opened 13 years ago

Closed 13 years ago

#1 closed defect (fixed)

Incorrect parsing of IPv6 literal in Host header

Reported by: id.seznam.cz/f49759d8b4c466810d3beaae455df049 Owned by: somebody
Priority: minor Milestone:
Component: nginx-core Version: 1.0.x
Keywords: ipv6 Cc:
uname -a: Linux encyklopedie.dev 2.6.32-openvz #1 SMP Wed Mar 23 13:25:59 CET 2011 x86_64 GNU/Linux
nginx -V: nginx: nginx version: nginx/1.0.1
nginx: TLS SNI support enabled
nginx: configure arguments: --prefix=/www/nginx --add-module=/root/nginx/trunk/szn/nginx_http_h264_streaming --add-module=/root/nginx/trunk/szn/nginx_upload --add-module=/root/nginx/trunk/szn/nginx_http_secure_download --conf-path=/www/nginx/doc/nginx.conf --error-log-path=/www/nginx/log/error.log --pid-path=/var/run/nginx.pid --lock-path=/www/nginx/lock/nginx.lock --http-log-path=/www/nginx/log/access.log --http-client-body-temp-path=/www/nginx/var/lib/body --http-proxy-temp-path=/www/nginx/lib/proxy --http-fastcgi-temp-path=/www/nginx/var/lib/fastcgi --with-debug --with-http_stub_status_module --with-http_flv_module --with-http_ssl_module --with-http_dav_module --with-http_geoip_module --with-ipv6

Description

Hello,

this is a bug-repost from http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=607418 which also includes a patch.

I've noticed that nginx incorrectly parses IPv6 addresses from the HTTP
requests Host header into its '$host' configuration variable. An HTTP
request (via IPv4 or IPv5) in the following form:

GET / HTTP/1.0
Host: [::1]

results in a value of only '[::' in $host (excluding my quotes).

However, the following request:

GET / HTTP/1.0
Host: [::1]:80

results in the correct value of '[::1]' in $host.

For 'longer' IPv6 addresses the result is that a full two octets can be
missing from the $host variable, e.g.:

GET / HTTP/1.0
Host: [fdf2:9468:665c:eaf6:2af6:c9ca:f24e:ae62]

results in only '[fdf2:9468:665c:eaf6:2af6:c9ca:f24e:' in $host.

After some experimentation it seems that the last colon and all
characters following it are omitted. This may be the way the 'port'
portion is normally stripped from IPv4 literal addresses.

This leads to a number of potential issues:

  1. Proxying

Consider the following configuration, which may be used to proxy traffic
to an upstream server that serves multiple, name-based virtual hosts:

location / {

proxy_pass http://localhost:8000;
proxy_set_header Host $host;

}

Due to the incorrect parsing of the Host header in the request, a
malformed Host header is sent in the HTTP request to the upstream
server, resulting in '400 Bad Request' from Apache at least.

If a website had an nginx reverse proxy server configured in this way, a
visitor to http://[fc00::1]/ would likely receive this error.

  1. Logs

Consider the following log format which is the same as the default
format, but prepended with '$host '. This may be used in virtual
hosting environments or by awstats to distinguish traffic for different
customers or websites:

log_format vhost '$host $remote_addr - $remote_user [$time_local] '

'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';

access_log /var/log/nginx/localhost.access.log vhost;

The resulting log entry is ambiguous, and may confused parsers:

[: ::1 - - [18/Dec/2010:06:29:42 +0000] "GET / HTTP/1.0" 404 169 "-" "-"

  1. Rewrites, access control, other uses of the $host variable

Obviously, any configuration that matches on the contents of the $host
variable can fail to work as expected due to this bug.

The value of $host may sometimes be used as a 'key' for caching (such as
the documented example for proxy_cache_key). In this case, it is
possible that two different sites (eg. on [fc00::1234] and [fc00::5678])
could be given the same key due to the incorrect parsing. In the most
extreme case this may cause one website's content to appear on the other
(if the upstream server and path part of the URI were the same).

As well as fixing the parsing of the IPv6 literal address, I suggest
nginx also sanitises it (e.g. removing unnecessary zeroes), otherwise a
malicious user could try to influence the behaviour of proxy_cache by
visiting [fc00::1], [fc00::01], [fc00::000:1], etc.

The bug is present in all the current nginx "stable" versions as well as in the latest 1.1.0 development unstable.

Change History (3)

comment:1 by Maxim Dounin, 13 years ago

Status: newaccepted

(Thank you, this is certainly a valid problem. We are aware of it, nevertheless many thanks for filling good bug.)

Currently IPv6 literals aren't supported. Unfortunately, the patch in question isn't enough to correctly support IPv6 literals: request line parsing should be fixed as well.

comment:2 by Valentin V. Bartenev, 13 years ago

In [4314/nginx]:

Added support for IP-literal in host header and request line (ticket #1).

Additional parsing logic added to correctly handle RFC 3986 compliant IPv6 and
IPvFuture characters enclosed in square brackets.

The host validation was completely rewritten. The behavior for non IP literals
was changed in a more proper and safer way:

  • Host part is now delimited either by the first colon or by the end of string if there's no colon. Previously the last colon was used as delimiter which allowed substitution of a port number in the $host variable. (e.g. Host: 127.0.0.1:9000:80)
  • Fixed stripping off the ending dot in the Host header when the host was also followed by a port number. (e.g. Host: nginx.com.:80)
  • Fixed upper case characters detection. Previously it was broken which led to wasting memory and CPU.

comment:3 by Maxim Dounin, 13 years ago

Resolution: fixed
Status: acceptedclosed

Fixed in 1.1.9.

Note: See TracTickets for help on using tickets.