Pound forwards requests with multiple `Transfer-Encoding: chunked` headers
kenballus opened this issue · comments
When I send the following request to Pound:
GET / HTTP/1.1\r\n
Host: a\r\n
Transfer-Encoding: chunked\r\n
Transfer-Encoding: chunked\r\n
\r\n
0\r\n
\r\n
It forwards the following to my backend:
GET / HTTP/1.1\r\n
Host: a\r\n
Transfer-Encoding: chunked\r\n
Transfer-Encoding: chunked\r\n
X-Forwarded-For: 172.19.0.1\r\n
X-Forwarded-Proto: http\r\n
X-Forwarded-Port: 80\r\n
\r\n
0\r\n
\r\n
Note that the two Transfer-Encoding headers are preserved. This is problematic for the many servers that misinterpret such requests, and can lead to request smuggling.
There are three potential fixes for this problem:
- Reject messages with multiple
Transfer-Encoding: chunked
headers. This is what Apache, Caddy, Envoy, HAProxy, nghttpx, Nginx, LiteSpeed, Squid, Traefik, Akamai, AWS, Azure, CloudFlare, Fastly, and Google Cloud do. - Normalize the request to have only one
Transfer-Encoding: chunked
header. This is what Apache Traffic Server does. - Buffer the request and use
Content-Length
instead. This is what H2O and Varnish do.
Hi Ben,
According to the HTTP specs, the Transfer-Encoding header can indeed be
used multiple times (RFC 2616, sect. 14.41 defines it as carrying a
comma-separated list of values (1#transfer-coding), and sect. 4.2
ibid. says that such headers are allowed to appear in multiple instances
in a message).
On the other hand, the Transfer-Encoding header in your example is
equivalent to
Transfer-Encoding: chunked, chunked
and the RFC says explicitly that the "chunked" transfer-coding must
not be applied more than once to a message-body (sect. 3.6). Therefore
I think the right course of action is to reject such messages as
invalid.
Regards,
Sergey
Fixed in 8d86d52