From: Willy Tarreau Date: Wed, 4 Nov 2026 15:00:35 +0000 (+0100) Subject: MINOR: http/hardening: implement hardening "reject-content-length-with-te" X-Git-Tag: v3.5-dev11~8 X-Git-Url: https://git.kaiwu.me/$%7BISSUES%7D/static/gitweb.js?a=commitdiff_plain;h=3bd127283f9f302bf63d9e8723da62a97b269734;p=haproxy.git MINOR: http/hardening: implement hardening "reject-content-length-with-te" 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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 81955ff1b..b1cafe91a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -34578,6 +34578,17 @@ http-hardening [from ] 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 diff --git a/include/haproxy/http-t.h b/include/haproxy/http-t.h index 89db7d573..66d8ae7e1 100644 --- a/include/haproxy/http-t.h +++ b/include/haproxy/http-t.h @@ -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 diff --git a/src/h1.c b/src/h1.c index 587af284f..d17413338 100644 --- 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; diff --git a/src/http.c b/src/http.c index cff8e5680..fa8ffb429 100644 --- a/src/http.c +++ b/src/http.c @@ -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 }