exploit different case matching schemes along the chain. This is
recommended on untrusted listeners.
+ - reject-underscore-in-header-name (inbound, request and response)
+ Rejects requests and responses in which one header field name contains
+ an underscore character ('_' or \x5C). This character is perfectly
+ permitted, but some application frameworks which create automatic
+ variables tend to already turn the dash ('-') into an underscore in
+ variable names, leading to an ambiguity with the underscore which can
+ result in the same variable name. This could be abused to bypass some
+ access-control policy for example. No standard HTTP header uses this,
+ so it is safe to enable on untrusted listeners.
+
/*
* Local variables:
* fill-column: 79
/* insert new masks below this line */
#define HTTP_HRD_REJ_DUP_HOST_HDR 0x00000001
#define HTTP_HRD_REJ_LCASE_METHOD 0x00000002
+#define HTTP_HRD_REJ_USCORE_HDR_NAM 0x00000004
/* insert new masks above this line */
#define HTTP_HRD_ALL 0xFFFFFFFF
/* turn it to lower case if needed */
if (isupper((unsigned char)*ptr) && h1m->flags & H1_MF_TOLOWER)
*ptr = tolower((unsigned char)*ptr);
+ else if (unlikely(*ptr == '_')) {
+ if ((h1m->state != H1_MSG_TRAILERS && http_harden(HTTP_HRD_REJ_USCORE_HDR_NAM))) {
+ state = H1_MSG_RQMETH;
+ goto http_msg_invalid;
+ }
+ }
}
EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, H1_MSG_HDR_NAME);
}
*/
phdr = h2_str_to_phdr(list[idx].n);
- for (i = !!phdr; i < list[idx].n.len; i++)
+ for (i = !!phdr; i < list[idx].n.len; i++) {
if ((uint8_t)(list[idx].n.ptr[i] - 'A') <= 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
goto fail;
+ if (list[idx].n.ptr[i] == '_' && http_harden(HTTP_HRD_REJ_USCORE_HDR_NAM))
+ goto fail;
+ }
}
/* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
*/
phdr = h2_str_to_phdr(list[idx].n);
- for (i = !!phdr; i < list[idx].n.len; i++)
+ for (i = !!phdr; i < list[idx].n.len; i++) {
if ((uint8_t)(list[idx].n.ptr[i] - 'A') <= 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
goto fail;
+ if (list[idx].n.ptr[i] == '_' && http_harden(HTTP_HRD_REJ_USCORE_HDR_NAM))
+ goto fail;
+ }
}
/* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
TRACE_ERROR("invalid characters in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
goto err;
}
+ if (c == '_' && http_harden(HTTP_HRD_REJ_USCORE_HDR_NAM)) {
+ TRACE_ERROR("hardening rejected underscore in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
+ goto err;
+ }
}
/* RFC 9114 10.3 Intermediary-Encapsulation Attacks
/* insert new hardening options below this line */
{ "reject-duplicate-host-header", HTTP_HRD_REJ_DUP_HOST_HDR, HTTP_DIR_REQ },
{ "reject-lowercase-method", HTTP_HRD_REJ_LCASE_METHOD, HTTP_DIR_REQ },
+ { "reject-underscore-in-header-name", HTTP_HRD_REJ_USCORE_HDR_NAM, HTTP_DIR_BOTH },
/* insert new hardening options above this line */
{ "all", HTTP_HRD_ALL, HTTP_DIR_BOTH },
{ NULL, 0 }