Commit Graph

159 Commits

Author SHA1 Message Date
Demi Marie Obenour
e30ddb7a3b HTTP: Do not allow multiple CRs before LF
This is not permitted by RFC9112.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
dab8c0e762 HTTP: Do not allow header lines with no colon
RFC9112 does not permit them.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
279ae488a4 HTTP: Reject hop-by-hop headers in HTTP/2 and HTTP/3 requests
RFC9113 and RFC9114 both require requests with connection-specific
headers to be treated as malformed, with the exception of "te: trailers".
Reject requests containing them.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
ae76c64300 HTTP: Reject invalid field values
RFC9110 is clear that the only CTRL character allowed in header values
is HTAB.  Conform to the standard, as Varnish, H2O, and (I suspect)
Hyper do.  This also makes the whitespace-stripping code simpler, as any
character that is less than 0x21 is either whitespace or rejected.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
b1c4b0757f HTTP: Reject invalid header names
HTTP headers must be an RFC9110 token, so only a subset of characters
are permitted.  RFC9113 and RFC9114 require rejecting invalid header
characters in HTTP/2 and HTTP/3 respectively, so reject them in HTTP/1.0
and HTTP/1.1 for consistency.  This also requires removing the ignore
hack for (presumably ancient) versions of IIS.
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
3897c97cc3 Strip leading and trailing whitespace from HTTP field values
Per RFC9110, HTTP field values never contain leading or trailing
whitespace.  Strip all such whitespace from HTTP and HTTP field values.
The HTTP/1.x parser already stripped spaces but didn't strip tabs, so
change the parser to strip tabs as well.  In HTTP/2+, the stripping is
done during validation.  This requires modifying the value.

There are three ways to modify the value:

1. Modify the data in-place with memmove().
2. Move the data pointer to point to after the leading whitespace.
3. Allocate a new buffer and replace the data pointer.

Both HPACK and QPACK decompression make a copy of the data, but some
code might assume that the data pointer of a field value can safely be
passed to ngx_pfree().  Therefore, the first option is chosen.  Existing
code ensures that header values are NUL-terminated, so the stripping
code NUL-pads header values to ensure that the stripped strings have at
least as many terminating NUL bytes as they did before being stripped.

The stripping code has been tested in a standalone program to make sure
that it works correctly, and it correctly strips leading and trailing
whitespace from a variety of strings.  This code has also been tested
with real HTTP/3 requests from Cloudflare's h3i tool.

Fixes: #598
2025-06-10 15:02:24 -04:00
Demi Marie Obenour
80b41e1002 HTTP: Use common header validation function for HTTP/2 and HTTP/3
The header validation required by HTTP/2 and HTTP/3 is identical, so use
a common function for both.  This will make it easier to add additional
validation in the future.  Move the function to ngx_http_parse.c so that
it can share code with the HTTP/1.x parser in the future.

No functional change intended.
2025-06-10 15:02:24 -04:00
Sergey Kandaurov
1a64c196a7 Proxy: proxy_pass_trailers directive.
The directive allows to pass upstream response trailers to client.
2024-09-13 16:47:56 +04:00
Vladimir Khomutov
0db94ba96a HTTP: removed unused r->port_start and r->port_end.
Neither r->port_start nor r->port_end were ever used.

The r->port_end is set by the parser, though it was never used by
the following code (and was never usable, since not copied by the
ngx_http_alloc_large_header_buffer() without r->port_start set).
2023-11-28 12:57:14 +03:00
Maxim Dounin
3aef1d693f Reworked multi headers to use linked lists.
Multi headers are now using linked lists instead of arrays.  Notably,
the following fields were changed: r->headers_in.cookies (renamed
to r->headers_in.cookie), r->headers_in.x_forwarded_for,
r->headers_out.cache_control, r->headers_out.link, u->headers_in.cache_control
u->headers_in.cookies (renamed to u->headers_in.set_cookie).

The r->headers_in.cookies and u->headers_in.cookies fields were renamed
to r->headers_in.cookie and u->headers_in.set_cookie to match header names.

The ngx_http_parse_multi_header_lines() and ngx_http_parse_set_cookie_lines()
functions were changed accordingly.

With this change, multi headers are now essentially equivalent to normal
headers, and following changes will further make them equivalent.
2022-05-30 21:25:33 +03:00
Maxim Dounin
7587778a33 Improved logging of invalid headers.
In 71edd9192f24 logging of invalid headers which were rejected with the
NGX_HTTP_PARSE_INVALID_HEADER error was restricted to just the "client
sent invalid header line" message, without any attempts to log the header
itself.

This patch returns logging of the header up to the invalid character and
the character itself.  The r->header_end pointer is now properly set
in all cases to make logging possible.

The same logging is also introduced when parsing headers from upstream
servers.
2021-06-28 18:01:20 +03:00
Maxim Dounin
9ab4d368af Disabled control characters and space in header names.
Control characters (0x00-0x1f, 0x7f), space, and colon were never allowed in
header names.  The only somewhat valid use is header continuation which nginx
never supported and which is explicitly obsolete by RFC 7230.

Previously, such headers were considered invalid and were ignored by default
(as per ignore_invalid_headers directive).  With this change, such headers
are unconditionally rejected.

It is expected to make nginx more resilient to various attacks, in particular,
with ignore_invalid_headers switched off (which is inherently unsecure, though
nevertheless sometimes used in the wild).
2021-06-28 18:01:18 +03:00
Maxim Dounin
0b66bd4be7 Disabled control characters in URIs.
Control characters (0x00-0x1f, 0x7f) were never allowed in URIs, and must
be percent-encoded by clients.  Further, these are not believed to appear
in practice.  On the other hand, passing such characters might make various
attacks possible or easier, despite the fact that currently allowed control
characters are not significant for HTTP request parsing.
2021-06-28 18:01:15 +03:00
Maxim Dounin
05395f4889 Disabled spaces in URIs (ticket #196).
From now on, requests with spaces in URIs are immediately rejected rather
than allowed.  Spaces were allowed in 31e9677b15a1 (0.8.41) to handle bad
clients.  It is believed that now this behaviour causes more harm than
good.
2021-06-28 18:01:13 +03:00
Maxim Dounin
5f85bb3714 Added CONNECT method rejection.
No valid CONNECT requests are expected to appear within nginx, since it
is not a forward proxy.  Further, request line parsing will reject
proper CONNECT requests anyway, since we don't allow authority-form of
request-target.  On the other hand, RFC 7230 specifies separate message
length rules for CONNECT which we don't support, so make sure to always
reject CONNECTs to avoid potential abuse.
2021-06-28 18:01:04 +03:00
Maxim Dounin
ce9971b2b5 Fixed parsing of absolute URIs with empty path (ticket #2079).
When the request line contains request-target in the absolute-URI form,
it can contain path-empty instead of a single slash (see RFC 7230, RFC 3986).
Previously, the ngx_http_parse_request_line() function only accepted empty
path when there was no query string.

With this change, non-empty query is also correctly handled.  That is,
request line "GET http://example.com?foo HTTP/1.1" is accepted and results
in $uri "/" and $args "foo".

Note that $request_uri remains "?foo", similarly to how spaces in URIs
are handled.  Providing "/?foo", similarly to how "/" is provided for
"GET http://example.com HTTP/1.1", requires allocation.
2020-12-10 20:09:30 +03:00
Ruslan Ermilov
3c84e4b705 Fixed header parsing with ignore_invalid_headers switched off.
The parsing was broken when the first character of the header name was invalid.

Based on a patch by Alan Kemp.
2019-10-15 14:46:10 +03:00
Maxim Dounin
85137dd2a6 Fixed URI normalization with merge_slashes switched off.
Previously, "/foo///../bar" was normalized into "/foo/bar"
instead of "/foo//bar".
2019-10-08 21:56:14 +03:00
Ruslan Ermilov
ed42131da6 The "/." and "/.." at the end of URI should be normalized. 2019-10-08 21:56:14 +03:00
Ruslan Ermilov
2ac24f1c88 Improved detection of broken percent encoding in URI. 2019-10-08 21:56:14 +03:00
Sergey Kandaurov
77c01f10a1 Detect runaway chunks in ngx_http_parse_chunked().
As defined in HTTP/1.1, body chunks have the following ABNF:

   chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF

where chunk-data is a sequence of chunk-size octets.

With this change, chunk-data that doesn't end up with CRLF at chunk-size
offset will be treated as invalid, such as in the example provided below:

4
SEE-THIS-AND-
4
THAT
0
2019-09-03 17:26:56 +03:00
Ruslan Ermilov
c804eb7748 Allowed digits, '+', '-', and '.' in scheme names as per RFC 3986. 2018-05-24 12:06:35 +03:00
Valentin Bartenev
9197a3c874 Parenthesized ASCII-related calculations.
This also fixes potential undefined behaviour in the range and slice filter
modules, caused by local overflows of signed integers in expressions.
2017-07-17 17:23:51 +03:00
Maxim Dounin
8449f750e6 Added missing "fall through" comments (ticket #1259).
Found by gcc7 (-Wimplicit-fallthrough).
2017-04-27 16:57:18 +03:00
Ruslan Ermilov
8ae2bc9320 Don't pretend we support HTTP major versions >1 as HTTP/1.1. 2017-04-25 23:39:13 +03:00
Maxim Dounin
82ec849271 Allowed '-' in method names.
It is used at least by SOAP (M-POST method, defined by RFC 2774) and
by WebDAV versioning (VERSION-CONTROL and BASELINE-CONTROL methods,
defined by RFC 3253).
2016-10-10 16:24:50 +03:00
Sergey Kandaurov
6299f5e914 Avoid left-shifting integers into the sign bit, which is undefined.
Found with UndefinedBehaviorSanitizer.
2016-07-07 21:02:28 +03:00
Maxim Dounin
e647c47f2a Added overflow checks for version numbers (ticket #762).
Both minor and major versions are now limited to 999 maximum.  In case of
r->http_minor, this limit is already implied by the code.  Major version,
r->http_major, in theory can be up to 65535 with current code, but such
values are very unlikely to become real (and, additionally, such values
are not allowed by RFC 7230), so the same test was used for r->http_major.
2016-05-18 16:21:32 +03:00
Ruslan Ermilov
4fe0a09942 Overflow detection in ngx_http_parse_chunked(). 2015-03-17 00:26:27 +03:00
Piotr Sikora
7e7589e746 Style: add whitespace between control statement and parentheses.
Signed-off-by: Piotr Sikora <piotr@cloudflare.com>
2014-07-08 03:03:13 -07:00
Vladimir Homutov
ed6780aaf1 Upstream: added the "$upstream_cookie_<name>" variables. 2014-04-29 12:28:41 +04:00
Piotr Sikora
ac1617915c Apply underscores_in_headers also to the first character.
Signed-off-by: Piotr Sikora <piotr@cloudflare.com>
2014-03-24 16:35:44 -07:00
Ruslan Ermilov
f7ff5e65d0 Teach ngx_http_parse_unsafe_uri() how to unescape URIs.
This fixes handling of escaped URIs in X-Accel-Redirect (ticket #316),
SSI (ticket #240), and DAV.
2013-12-23 18:12:00 +04:00
Ruslan Ermilov
336bcb22d1 Detect more unsafe URIs in ngx_http_parse_unsafe_uri().
The following URIs were considered safe: "..", "../foo", and "/foo/..".
2013-12-23 18:11:56 +04:00
Ruslan Ermilov
d47c435e9e Proper backtracking after space in a request line. 2013-11-19 06:57:58 +04:00
Maxim Dounin
0a6efeee71 Minor ngx_http_parse_request_line() optimization.
Noted by Nils Kuhnhenn.
2013-08-21 12:51:31 +04:00
Maxim Dounin
88fc0f793e Fixed ngx_http_parse_chunked() minimal length calculation.
Minimal data length we expect for further calls was calculated incorrectly
if parsing stopped right after parsing chunk size.  This might in theory
affect clients and/or backends using LF instead of CRLF.

Patch by Dmitry Popov.
2013-06-28 13:55:05 +04:00
Maxim Dounin
dc5c6928fb Fixed debug logging in ngx_http_parse_complex_uri().
The *u previously logged isn't yet initialized at this point, and
Valgrind complains.
2013-06-05 19:45:08 +04:00
Maxim Dounin
818807d71e Fixed chunk size parsing. 2013-05-06 14:03:24 +04:00
Valentin Bartenev
2686cb4452 Preliminary experimental support for SPDY draft 2. 2013-03-20 10:36:57 +00:00
Maxim Dounin
6ddf23bdc4 Request body: adjust b->pos when chunked parsing done.
This is a nop for the current code, though will allow to correctly parse
pipelined requests.
2012-11-21 01:02:56 +00:00
Maxim Dounin
df74d88156 Request body: chunked parsing moved to ngx_http_parse.c from proxy.
No functional changes.
2012-11-21 00:59:16 +00:00
Maxim Dounin
f83598a359 Win32: normalization of trailing dot inside uri.
Windows treats "/directory./" identical to "/directory/".  Do the same
when working on Windows.  Note that the behaviour is different from one
with last path component (where multiple spaces and dots are ignored by
Windows).
2012-06-05 13:37:29 +00:00
Ruslan Ermilov
47a04aaa27 Fixed spelling in multiline C comments. 2012-04-03 07:37:31 +00:00
Maxim Konovalov
acf6c79ac7 For the sake of case/switch code readability, 'fall through'
comments added.
2012-03-19 14:57:29 +00:00
Maxim Dounin
d1ed97b18b Headers with null character are now rejected.
Headers with NUL character aren't allowed by HTTP standard and may cause
various security problems.  They are now unconditionally rejected.
2012-03-15 11:27:57 +00:00
Maxim Konovalov
f8d59e33f3 Copyright updated. 2012-01-18 15:07:43 +00:00
Valentin Bartenev
1373558163 Added support for IP-literal in the 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 of 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.
2011-11-28 09:15:33 +00:00
Maxim Dounin
f2fcf11b25 Protocol version parsing in ngx_http_parse_status_line().
Once we know protocol version, set u->headers_in.connection_close to indicate
implicitly assumed connection close with HTTP before 1.1.
2011-09-15 19:22:35 +00:00
Igor Sysoev
aa6936e61a style fix 2010-06-23 16:34:54 +00:00