recommended to enable on untrusted listeners. Note that this applies
only after "reject-underscore-in-trailer-name" was accepted.
+ - delete-unregistered-header-fields (inbound, request and response)
+ Deletes from requests and responses any header field whose name starts
+ with 'x-' (upper or lower case). These header 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, as well as in old browsers that
+ were trying to work around known server bugs (e.G. "X-Pad"). While it
+ would be risky to block such requests, it is safe and even recommended
+ to delete such headers from inbound internet requests. It is preferable
+ not to do it on responses however when applications uses such header
+ fields to report information to HAProxy.
+
- 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
#define HTTP_HRD_REJ_USCORE_TLR_NAM 0x00000008
#define HTTP_HRD_DEL_USCORE_HDR_NAM 0x00000010
#define HTTP_HRD_DEL_USCORE_TLR_NAM 0x00000020
+#define HTTP_HRD_DEL_UNREG_HDR 0x00000040
/* insert new masks above this line */
#define HTTP_HRD_ALL 0xFFFFFFFF
break;
}
+ /* we may have to delete unregistered header names (X-) */
+ if (unlikely(h1m->state != H1_MSG_TRAILERS && http_harden(HTTP_HRD_DEL_UNREG_HDR))) {
+ if (n.len > 1 && n.ptr[1] == '-' &&
+ (n.ptr[0] == 'x' || n.ptr[0] == 'X'))
+ break;
+ }
+
if (isteqi(n, ist("transfer-encoding"))) {
ret = h1_parse_xfer_enc_header(h1m, v);
if (ret < 0) {
continue;
}
+ /* we may have to delete unregistered header names (X-) */
+ if (unlikely(http_harden(HTTP_HRD_DEL_UNREG_HDR))) {
+ 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;
+ }
+
if (unlikely(!(fields & H2_PHDR_FND_NONE))) {
/* no more pseudo-headers, time to build the request line */
sl = h2_prepare_htx_reqline(fields, phdr_val, htx, msgf);
continue;
}
+ /* we may have to delete unregistered header names (X-) */
+ if (unlikely(http_harden(HTTP_HRD_DEL_UNREG_HDR))) {
+ 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;
+ }
+
if (!(fields & H2_PHDR_FND_NONE)) {
/* no more pseudo-headers, time to build the status line */
sl = h2_prepare_htx_stsline(fields, phdr_val, htx, msgf);
continue;
}
+ /* we may have to delete unregistered header names (X-) */
+ if (unlikely(http_harden(HTTP_HRD_DEL_UNREG_HDR))) {
+ if (list[hdr_idx].n.len > 1 && list[hdr_idx].n.ptr[1] == '-' &&
+ (list[hdr_idx].n.ptr[0] == 'x' || list[hdr_idx].n.ptr[0] == 'X')) {
+ /* skip it, so it won't be added */
+ ++hdr_idx;
+ continue;
+ }
+ }
+
if (isteq(list[hdr_idx].n, ist("host"))) {
struct ist prev_auth = authority;
{ "reject-underscore-in-trailer-name", HTTP_HRD_REJ_USCORE_TLR_NAM, HTTP_DIR_BOTH },
{ "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 },
/* insert new hardening options above this line */
{ "all", HTTP_HRD_ALL, HTTP_DIR_BOTH },
{ NULL, 0 }