]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http/hardening: implement hardening "reject-content-length-with-te"
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 15:00:35 +0000 (16:00 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 21:45:33 +0000 (22:45 +0100)
Rejects requests and responses having both a Content-Length header
field and a Transfer-Encoding header field. While these are permitted
by HTTP/1.1 (Transfer-Encoding wins), it can cause problems when the
message first passed through an HTTP/1.0 gateway that does not
recognize Transfer-Encoding, and can desynchronize this gateway from
the rest of the communication. These are still seldom seen in legacy
client or server applications, sometimes in relation with compression
and/or caching. While HAProxy properly normalizes them, it is generally
safe to reject them on public facing listeners.

doc/configuration.txt
include/haproxy/http-t.h
src/h1.c
src/http.c

index 81955ff1b2a9bf327a5db0e95deb3dbf6e5af7ae..b1cafe91abfdfc43eb5c4407d1f43144d69e42a3 100644 (file)
@@ -34578,6 +34578,17 @@ http-hardening <name> [from <name2>]
         safe and even recommended to delete such trailers from inbound internet
         requests.
 
+  - reject-content-length-with-te (inbound request and response)
+        Rejects requests and responses having both a Content-Length header
+        field and a Transfer-Encoding header field. While these are permitted
+        by HTTP/1.1 (Transfer-Encoding wins), it can cause problems when the
+        message first passed through an HTTP/1.0 gateway that does not
+        recognize Transfer-Encoding, and can desynchronize this gateway from
+        the rest of the communication. These are still seldom seen in legacy
+        client or server applications, sometimes in relation with compression
+        and/or caching. While HAProxy properly normalizes them, it is generally
+        safe to reject them on public facing listeners.
+
   - reject-ctl-in-header-trailer (inbound request and response)
         Rejects requests and responses which contain control characters in
         their header or trailer field values (codes 0-8,10-31,127). These ones
index 89db7d57377e377a85e9ad48744a5f94b0de6c4f..66d8ae7e139e684e8278a3b714e52734cd6b3343 100644 (file)
@@ -251,6 +251,7 @@ struct http_violation {
 #define HTTP_HRD_DEL_ALL_TLR                0x00000100
 #define HTTP_HRD_REJ_HDR_FOLD               0x00000200
 #define HTTP_HRD_REJ_CTL_IN_HDR             0x00000400
+#define HTTP_HRD_REJ_CL_TE                  0x00000800
 /* insert new masks above this line */
 #define HTTP_HRD_ALL                        0xFFFFFFFF
 
index 587af284f86cc2ed806213109502b96080e05cbc..d174133382fa6e09a56bac333a01a2e61124cad1 100644 (file)
--- a/src/h1.c
+++ b/src/h1.c
@@ -1356,6 +1356,11 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                state = H1_MSG_DATA;
                if (h1m->flags & H1_MF_XFER_ENC) {
                        if (h1m->flags & H1_MF_CLEN) {
+                               if (http_harden(HTTP_HRD_REJ_CL_TE)) {
+                                       /* strict mode: we don't want to accept that one */
+                                       goto http_msg_invalid;
+                               }
+
                                /* T-E + C-L: force close and remove C-L */
                                if (!h1_do_not_close_on_insecure_t_e)
                                        h1m->flags |= H1_MF_CONN_CLO;
index cff8e568078b8d1ce5c3a45283e49be5a9651ff0..fa8ffb4294b5cc9a9d2474d32534e237a91a368b 100644 (file)
@@ -1786,6 +1786,7 @@ const struct http_hardening_kw http_hardening_kws[] = {
        { "delete-all-trailer-fields",         HTTP_HRD_DEL_ALL_TLR, HTTP_DIR_BOTH },
        { "reject-header-trailer-folding",     HTTP_HRD_REJ_HDR_FOLD, HTTP_DIR_BOTH },
        { "reject-ctl-in-header-trailer",      HTTP_HRD_REJ_CTL_IN_HDR, HTTP_DIR_BOTH },
+       { "reject-content-length-with-te",     HTTP_HRD_REJ_CL_TE, HTTP_DIR_BOTH },
        /* insert new hardening options above this line */
        { "all",                            HTTP_HRD_ALL,              HTTP_DIR_BOTH },
        { NULL, 0 }