]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mux-h1: Reject HTTP/1.0 GET/HEAD/DELETE requests with a payload
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 21 Sep 2021 16:44:55 +0000 (18:44 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 28 Sep 2021 14:21:11 +0000 (16:21 +0200)
This kind of requests is now forbidden and rejected with a
413-Payload-Too-Large error.

It is unexpected to have a payload for GET/HEAD/DELETE requests. It is
explicitly allowed in HTTP/1.1 even if some servers may reject such
requests. However, HTTP/1.0 is not clear on this point and some old servers
don't expect any payload and never look for body length (via Content-Length
or Transfer-Encoding headers).

It means that some intermediaries may properly handle the payload for
HTTP/1.0 GET/HEAD/DELETE requests, while some others may totally ignore
it. That may lead to security issues because a request smuggling attack is
possible.

To prevent any issue, those requests are now rejected.

See also httpwg/http-core#904

src/mux_h1.c

index 3a02d11fcdb41b9fbe5a408199bf0051c1fcc13b..a391ab12840e14e06d6b9c6ecd560a764c4aefb8 100644 (file)
@@ -1402,6 +1402,24 @@ static size_t h1_handle_headers(struct h1s *h1s, struct h1m *h1m, struct htx *ht
                goto end;
        }
 
+
+       /* Reject HTTP/1.0 GET/HEAD/DELETE requests with a payload. There is a
+        * payload if the c-l is not null or the the payload is chunk-encoded.
+        * A parsing error is reported but a A 413-Payload-Too-Large is returned
+        * instead of a 400-Bad-Request.
+        */
+       if (!(h1m->flags & (H1_MF_RESP|H1_MF_VER_11)) &&
+           (((h1m->flags & H1_MF_CLEN) && h1m->body_len) || (h1m->flags & H1_MF_CHNK)) &&
+           (h1sl.rq.meth == HTTP_METH_GET || h1sl.rq.meth == HTTP_METH_HEAD || h1sl.rq.meth == HTTP_METH_DELETE)) {
+               h1s->flags |= H1S_F_PARSING_ERROR;
+               htx->flags |= HTX_FL_PARSING_ERROR;
+               h1s->h1c->errcode = 413;
+               TRACE_ERROR("HTTP/1.0 GET/HEAD/DELETE request with a payload forbidden", H1_EV_RX_DATA|H1_EV_RX_HDRS|H1_EV_H1S_ERR, h1s->h1c->conn, h1s);
+               h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
+               ret = 0;
+               goto end;
+       }
+
        /* If websocket handshake, search for the websocket key */
        if ((h1m->flags & (H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET)) ==
            (H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET)) {