]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http/hardening: add "delete-unregistered-trailer-fields"
authorWilly Tarreau <w@1wt.eu>
Tue, 3 Nov 2026 15:25:49 +0000 (16:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 21:45:32 +0000 (22:45 +0100)
This is the same as for the headers, but this time for the trailers. Better
keep them separated as trailers are used even worse than headers these days.

Similarly as for the underscore, unwanted trailers are dropped early for
h1.

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

index 8058187927b1f621ee3f4d85fd5adb69bbe53148..acb31bd6d8cba25a8267eb83db3dba7f21bebce8 100644 (file)
@@ -34558,6 +34558,15 @@ http-hardening <name> [from <name2>]
         not to do it on responses however when applications uses such header
         fields to report information to HAProxy.
 
+  - delete-unregistered-trailer-fields (inbound, request and response)
+        Deletes from requests and responses any trailer field whose name starts
+        with 'x-' (upper or lower case). These trailer fields are not
+        registered with IANA and are not used across the internet by standard
+        components. They may appear in untrusted requests in attacks trying to
+        exploit some backend framework weaknesses however, so it is generally
+        safe and even recommended to delete such trailers from inbound internet
+        requests.
+
   - reject-duplicate-host-header (inbound request)
         Rejects requests containing more than one "Host" header field, even if
         valid and identical. This is recommended on untrusted listeners. Note that
index a88367aad110cd8cb0d7fba9853358f9124bbfe4..e5019bb3d3f0f62101deccafcf56576d00f31c71 100644 (file)
@@ -247,6 +247,7 @@ struct http_violation {
 #define HTTP_HRD_DEL_USCORE_HDR_NAM         0x00000010
 #define HTTP_HRD_DEL_USCORE_TLR_NAM         0x00000020
 #define HTTP_HRD_DEL_UNREG_HDR              0x00000040
+#define HTTP_HRD_DEL_UNREG_TLR              0x00000080
 /* insert new masks above this line */
 #define HTTP_HRD_ALL                        0xFFFFFFFF
 
index 7fc979db488cced311dc6834d36764e039aa37ea..052e49e2609a582d3419e225f388d7d4f9e30480 100644 (file)
--- a/src/h1.c
+++ b/src/h1.c
@@ -1053,7 +1053,8 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                                }
 
                                /* we may have to delete unregistered header names (X-) */
-                               if (unlikely(h1m->state != H1_MSG_TRAILERS && http_harden(HTTP_HRD_DEL_UNREG_HDR))) {
+                               if (unlikely((h1m->state != H1_MSG_TRAILERS && http_harden(HTTP_HRD_DEL_UNREG_HDR)) ||
+                                            (h1m->state == H1_MSG_TRAILERS && http_harden(HTTP_HRD_DEL_UNREG_TLR)))) {
                                        if (n.len > 1 && n.ptr[1] == '-' &&
                                            (n.ptr[0] == 'x' || n.ptr[0] == 'X'))
                                                break;
index 94a19a0364ed187cd9ef16124fae820124774880..a4df4e177c5532782e34429167122bbbbbcf1611 100644 (file)
@@ -1782,6 +1782,7 @@ const struct http_hardening_kw http_hardening_kws[] = {
        { "delete-underscore-in-header-name", HTTP_HRD_DEL_USCORE_HDR_NAM, HTTP_DIR_BOTH },
        { "delete-underscore-in-trailer-name", HTTP_HRD_DEL_USCORE_TLR_NAM, HTTP_DIR_BOTH },
        { "delete-unregistered-header-fields",HTTP_HRD_DEL_UNREG_HDR, HTTP_DIR_BOTH },
+       { "delete-unregistered-trailer-fields",HTTP_HRD_DEL_UNREG_TLR, HTTP_DIR_BOTH },
        /* insert new hardening options above this line */
        { "all",                            HTTP_HRD_ALL,              HTTP_DIR_BOTH },
        { NULL, 0 }
index b465b218b1f3349bca662d7955076e56e728b640..39f4cb352e46958c80f95a5de75a3bf3c6a93261 100644 (file)
@@ -2085,6 +2085,14 @@ enum http_parser_status http_trailers_to_htx(struct http_hdr *list, struct htx *
                        continue;
                }
 
+               /* we may have to delete unregistered header names (X-) */
+               if (unlikely(http_harden(HTTP_HRD_DEL_UNREG_TLR))) {
+                       if (list[idx].n.len > 1 && list[idx].n.ptr[1] == '-' &&
+                           (list[idx].n.ptr[0] == 'x' || list[idx].n.ptr[0] == 'X'))
+                               /* skip it, so it won't be added */
+                               continue;
+               }
+
                /* trim leading/trailing LWS as per RC9113#8.2.1 */
                for (v = list[idx].v; v.len; v.len--) {
                        if (unlikely(HTTP_IS_LWS(*v.ptr)))