ATS does not validate `Content-Length` values for HTTP/1.1 requests that contain a `Transfer-Encoding: chunked` header.
kenballus opened this issue · 2 comments
The bug
RFC 9110 uses the following ABNF rule to define the acceptable values of the Content-Length
header:
Content-Length = 1*DIGIT
When ATS receives a request with no Transfer-Encoding
header, and an invalid Content-Length
header, it correctly rejects the request.
When ATS receives a request with a Transfer-Encoding: chunked
header, and an invalid Content-Length
header, it strips the Content-Length
header out of the request, but does not reject the request.
RFC 9110 is clear that this is something a send MUST not do:
Likewise, a sender MUST NOT forward a message with a Content-Length header field value that does not match the ABNF above, with one exception: a recipient of a Content-Length header field value consisting of the same decimal value repeated as a comma-separated list (e.g, "Content-Length: 42, 42") MAY either reject the message as invalid or replace that invalid field value with a single instance of the decimal value, since this likely indicates that a duplicate was generated or combined by an upstream message processor.
Reproducing the bug
To verify this for yourself, try sending the following request to ATS:
POST / HTTP/1.1\r\n
Host: a\r\n
Content-Length: blahblahblah\r\n
Transfer-Encoding: chunked\r\n
\r\n
1\r\n
Z\r\n
0\r\n
\r\n
It should forward something like the following to its backend:
POST / HTTP/1.1\r\n
Host: a\r\n
Client-ip: 172.19.0.1\r\n
X-Forwarded-For: 172.19.0.1\r\n
Via: http/1.1 traffic_server[f768a0a3-f9d8-4b7a-841a-4afc6bb85500] (ApacheTrafficServer/10.0.0)\r\n
Transfer-Encoding: chunked\r\n
\r\n
1\r\n
Z\r\n
0\r\n
\r\n
You can reproduce my experimental setup exactly using the HTTP Garden. Just build the Garden, and run the following command at the repl:
transducers ats; payload 'POST / HTTP/1.1\r\nHost: a\r\nContent-Length: blahblahblah\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nZ\r\n0\r\n\r\n'; transduce
You should see something like this:
[1]: 'POST / HTTP/1.1\r\nHost: a\r\nContent-Length: blahblahblah\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nZ\r\n0\r\n\r\n'
⬇️ ats
[2]: 'POST / HTTP/1.1\r\nHost: a\r\nClient-ip: 172.19.0.1\r\nX-Forwarded-For: 172.19.0.1\r\nVia: http/1.1 traffic_server[82766f05-99c1-4da5-ae53-267e3c448e08] (ApacheTrafficServer/10.0.0)\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nZ\r\n0\r\n\r\n'
The fact that the message was forwarded demonstrates the bug.
Versions
Traffic Server 10.0.0-0 Feb 2 2024 03:29:51 buildkitsandbox
traffic_server: using root directory '/usr/local/trafficserver'
ats - traffic_server - 10.0.0 - (build # 0 on Feb 2 2024 at 03:15:13)
$ uname -a
Linux 69a420df15e4 6.7.2-arch1-2 #1 SMP PREEMPT_DYNAMIC Wed, 31 Jan 2024 09:22:15 +0000 x86_64 GNU/Linux
The behavior is based on this paragraph.
https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.3
If a message is received with both a Transfer-Encoding and a Content-Length header field, the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and ought to be handled as an error. An intermediary that chooses to forward the message MUST first remove the received Content-Length field and process the Transfer-Encoding (as described below) prior to forwarding the message downstream.
Yep; I think you're right. Closing the issue.