diff --git a/doc/configuration.txt b/doc/configuration.txt index ae9ca5c6d..c8ec013b7 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -6206,6 +6206,8 @@ option forwarded (*) X - X X option h1-case-adjust-bogus-client (*) X X X - option h1-case-adjust-bogus-server (*) X - X X option http-buffer-request (*) X X X X +option http-drop-request-trailers (*) X - - X +option http-drop-response-trailers (*) X - X - option http-ignore-probes (*) X X X - option http-keep-alive (*) X X X X option http-no-delay (*) X X X X @@ -10364,6 +10366,50 @@ no option http-buffer-request See also : "option http-no-delay", "timeout http-request", "http-request wait-for-body" +option http-drop-request-trailers +no option http-drop-request-trailers + Drop the HTTP trailers from the request when sent to the server + + May be used in the following contexts: http + + May be used in sections : defaults | frontend | listen | backend + yes | no | no | yes + + Arguments : none + + When this option is enabled, any HTTP trailers found in a request will be + dropped before sending it to the server. + + RFC9110#section-6.5.1 stated that trailer fields could be merged into the + header fields. It should be done on purpose, but it may be a problem for some + applications, espcially if malicious clients hide sensitive header fields in + the trailers part and some intermediaries merge them with headers with no + specific checks. In that case, this option can be enabled on the backend to + drop any trailer fields found in requests before sending them to the server. + + If this option has been enabled in a "defaults" section, it can be disabled + in a specific instance by prepending the "no" keyword before it. + + See also: "option http-drop-response-trailers" + +option http-drop-response-trailers +no option http-drop-response-trailers + Drop the HTTP trailers from the response when sent to the client + + May be used in the following contexts: http + + May be used in sections : defaults | frontend | listen | backend + yes | yes | yes | no + + Arguments : none + + This option is similar to "option http-drop-request-trailers" but it must be + used to drop trailer fields from responses before sending them to clients. + + If this option has been enabled in a "defaults" section, it can be disabled + in a specific instance by prepending the "no" keyword before it. + + See also: "option http-drop-request-trailers" option http-ignore-probes no option http-ignore-probes diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index 6e6b8fe62..0ea2fd95b 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -114,8 +114,9 @@ enum PR_SRV_STATE_FILE { #define PR_O_HTTP_CLO 0x01000000 /* HTTP close mode (httpclose) */ #define PR_O_HTTP_SCL 0x02000000 /* HTTP server close mode (http-server-close) */ #define PR_O_HTTP_MODE 0x03000000 /* MASK to retrieve the HTTP mode */ -/* unused: 0x04000000 */ -/* unused: 0x08000000 */ + +#define PR_O_HTTP_DROP_REQ_TRLS 0x04000000 /* Drop the request trailers when forwarding to the server */ +#define PR_O_HTTP_DROP_RES_TRLS 0x08000000 /* Drop response trailers when forwarding to the client */ #define PR_O_TCPCHK_SSL 0x10000000 /* at least one TCPCHECK connect rule requires SSL */ #define PR_O_CONTSTATS 0x20000000 /* continuous counters */ diff --git a/src/h1.c b/src/h1.c index faf18ff13..2a4f6ccf7 100644 --- a/src/h1.c +++ b/src/h1.c @@ -1242,7 +1242,6 @@ int h1_headers_to_hdr_list(char *start, const char *stop, goto http_msg_invalid; } } - break; default: diff --git a/src/h3.c b/src/h3.c index 69528147b..0f15a8935 100644 --- a/src/h3.c +++ b/src/h3.c @@ -1818,6 +1818,11 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx) TRACE_ENTER(H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); hdr = 0; + + /* Skip the trailers because the corresponding conf option was set */ + if (qcs->qcc->proxy->options & PR_O_HTTP_DROP_RES_TRLS) + goto skip_trailers; + for (blk = htx_get_head_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) { type = htx_get_blk_type(blk); @@ -1842,6 +1847,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx) } } + skip_trailers: if (!hdr) { /* No headers encoded here so no need to generate a H3 HEADERS * frame. Mux will send an empty QUIC STREAM frame with FIN. diff --git a/src/mux_h1.c b/src/mux_h1.c index 490391c4e..17dd74652 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -3371,6 +3371,11 @@ static size_t h1_make_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *htx ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) goto nextblk; + /* Skip the trailers because the corresponding conf option was set */ + if ((!(h1m->flags & H1_MF_RESP) && (h1c->px->options & PR_O_HTTP_DROP_RES_TRLS)) || + ((h1m->flags & H1_MF_RESP) && (h1c->px->options & PR_O_HTTP_DROP_REQ_TRLS))) + goto nextblk; + n = htx_get_blk_name(htx, blk); v = htx_get_blk_value(htx, blk); diff --git a/src/mux_h2.c b/src/mux_h2.c index dbda2d34b..e739c8aee 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -7410,6 +7410,12 @@ static size_t h2s_make_trailers(struct h2s *h2s, struct htx *htx) /* get trailers. */ hdr = 0; + + /* Skip the trailers because the corresponding conf option was set */ + if ((!(h2c->flags & H2_CF_IS_BACK) && (h2c->proxy->options & PR_O_HTTP_DROP_RES_TRLS)) || + ((h2c->flags & H2_CF_IS_BACK) && (h2c->proxy->options & PR_O_HTTP_DROP_REQ_TRLS))) + goto skip_trailers; + for (blk = htx_get_head_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) { type = htx_get_blk_type(blk); @@ -7434,6 +7440,7 @@ static size_t h2s_make_trailers(struct h2s *h2s, struct htx *htx) } } + skip_trailers: /* marker for end of trailers */ list[hdr].n = ist(""); diff --git a/src/proxy.c b/src/proxy.c index 8d87bf85c..d89f326c2 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -87,6 +87,8 @@ const struct cfg_opt cfg_opts[] = { "contstats", PR_O_CONTSTATS, PR_CAP_FE, 0, 0 }, { "dontlognull", PR_O_NULLNOLOG, PR_CAP_FE, 0, 0 }, { "http-buffer-request", PR_O_WREQ_BODY, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP }, + { "http-drop-request-trailers", PR_O_HTTP_DROP_REQ_TRLS, PR_CAP_BE, 0, PR_MODE_HTTP }, + { "http-drop-response-trailers", PR_O_HTTP_DROP_RES_TRLS, PR_CAP_FE, 0, PR_MODE_HTTP }, { "http-ignore-probes", PR_O_IGNORE_PRB, PR_CAP_FE, 0, PR_MODE_HTTP }, { "idle-close-on-response", PR_O_IDLE_CLOSE_RESP, PR_CAP_FE, 0, PR_MODE_HTTP }, { "prefer-last-server", PR_O_PREF_LAST, PR_CAP_BE, 0, PR_MODE_HTTP },