From fd5d59967ad780563298a176db6e657f22831d50 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 28 Feb 2025 13:35:13 +0100 Subject: [PATCH] MINOR: h1: permit to relax the websocket checks for missing mandatory headers At least one user would like to allow a standards-violating client setup WebSocket connections through haproxy to a standards-violating server that accepts them. While this should of course never be done over the internet, it can make sense in the datacenter between application components which do not need to mask the data, so this typically falls into the situation of what the "accept-unsafe-violations-in-http-request" option and the "accept-unsafe-violations-in-http-response" option are made for. See GH #2876 for more context. This patch relaxes the test on the "Sec-Websocket-Key" header field in the request, and of the "Sec-Websocket-Accept" header in the response when these respective options are set. The doc was updated to reference this addition. This may be backported to 3.1 but preferably not further. --- doc/configuration.txt | 6 ++++++ src/mux_h1.c | 27 ++++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 942198d49..941073c92 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -9444,6 +9444,9 @@ no option accept-unsafe-violations-in-http-request different protocol names (e.g. RTSP), and multiple digits for both the major and the minor version. + * In H1 only, WebSocket (RFC6455) requests failing to present a valid + "Sec-Websocket-Key" header field will be accepted. + This option should never be enabled by default as it hides application bugs and open security breaches. It should only be deployed after a problem has been confirmed. @@ -9494,6 +9497,9 @@ no option accept-unsafe-violations-in-http-response different protocol names (e.g. RTSP), and multiple digits for both the major and the minor version. + * In H1 only, WebSocket (RFC6455) responses failing to present a valid + "Sec-Websocket-Accept" header field will be accepted. + This option should never be enabled by default as it hides application bugs and open security breaches. It should only be deployed after a problem has been confirmed. diff --git a/src/mux_h1.c b/src/mux_h1.c index c355edd0b..bf7fbaca5 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -1850,7 +1850,7 @@ static void h1_set_tunnel_mode(struct h1s *h1s) * responsible for the generation of a key. This happens when a h2 client is * interfaced with a h1 server. * - * Returns 0 if no key found or invalid key + * Returns 0 if no key found or invalid key. The message is not modified. */ static int h1_search_websocket_key(struct h1s *h1s, struct h1m *h1m, struct htx *htx) { @@ -1900,11 +1900,9 @@ static int h1_search_websocket_key(struct h1s *h1s, struct h1m *h1m, struct htx } } - /* missing websocket key, reject the message */ - if (!ws_key_found) { - htx->flags |= HTX_FL_PARSING_ERROR; + /* missing websocket key, invalid message */ + if (!ws_key_found) return 0; - } return 1; } @@ -1986,13 +1984,24 @@ static size_t h1_handle_headers(struct h1s *h1s, struct h1m *h1m, struct htx *ht if ((h1m->flags & (H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET)) == (H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET)) { int ws_ret = h1_search_websocket_key(h1s, h1m, htx); + if (!ws_ret) { - h1s->flags |= H1S_F_PARSING_ERROR; - TRACE_ERROR("missing/invalid websocket key, reject H1 message", H1_EV_RX_DATA|H1_EV_RX_HDRS|H1_EV_H1S_ERR, h1s->h1c->conn, h1s); h1_capture_bad_message(h1s->h1c, h1s, h1m, buf); - ret = 0; - goto end; + if ((!(h1m->flags & H1_MF_RESP) && !(h1s->h1c->px->options2 & PR_O2_REQBUG_OK)) || + ((h1m->flags & H1_MF_RESP) && !(h1s->h1c->px->options2 & PR_O2_RSPBUG_OK))) { + htx->flags |= HTX_FL_PARSING_ERROR; + h1s->flags |= H1S_F_PARSING_ERROR; + TRACE_ERROR("missing/invalid websocket key, reject H1 message", + H1_EV_RX_DATA|H1_EV_RX_HDRS|H1_EV_H1S_ERR, h1s->h1c->conn, h1s); + + ret = 0; + goto end; + } else { + TRACE_ERROR("missing/invalid websocket key, but accepting this " + "violation according to configuration", + H1_EV_RX_DATA|H1_EV_RX_HDRS|H1_EV_H1S_ERR, h1s->h1c->conn, h1s); + } } }