MINOR: proxy: Add options to drop HTTP trailers during message forwarding

In RFC9110, it is stated that trailers could be merged with the
headers. While it should be performed with a speicial care, it may be a
problem for some applications. To avoid any trouble with such applications,
two new options were added to drop trailers during the message forwarding.

On the backend, "http-drop-request-trailers" option can be enabled to drop
trailers from the requests before sending them to the server. And on the
frontend, "http-drop-response-trailers" option can be enabled to drop
trailers from the responses before sending them to the client. The options
can be defined in defaults sections and disabled with "no" keyword.

This patch should fix the issue #2930.
This commit is contained in:
Christopher Faulet 2025-04-15 15:36:19 +02:00
parent 044ef9b3d6
commit 5200203677
7 changed files with 69 additions and 3 deletions

View File

@ -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

View File

@ -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 */

View File

@ -1242,7 +1242,6 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
goto http_msg_invalid;
}
}
break;
default:

View File

@ -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.

View File

@ -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);

View File

@ -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("");

View File

@ -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 },