This keyword covers all known keywords together. It is essentially used
to enable or disable all checks at once.
+ - 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
+ even if not rejected, duplicate host header fields are folded into a
+ single one.
/*
* Local variables:
*/
#define HTTP_HRD_NONE 0x00000000
/* insert new masks below this line */
+#define HTTP_HRD_REJ_DUP_HOST_HDR 0x00000001
/* insert new masks above this line */
#define HTTP_HRD_ALL 0xFFFFFFFF
ptr = v.ptr; /* Set ptr on the error */
goto http_msg_invalid;
}
- /* if the same host, skip it */
+ /* if the same host, skip or reject it */
+ if (http_harden(HTTP_HRD_REJ_DUP_HOST_HDR)) {
+ state = H1_MSG_HDR_L2_LWS;
+ ptr = v.ptr; /* Set ptr on the error */
+ goto http_msg_invalid;
+ }
break;
}
}
uint32_t data_ofs = htx->data; /* used to rollback on error */
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
uint32_t fields; /* bit mask of H2_PHDR_FND_* */
+ int host_cnt = 0;
uint32_t idx;
int ck, lck; /* cookie index and last cookie index */
int phdr;
}
if (isteq(list[idx].n, ist("host"))) {
- /* skip duplicates */
- if (fields & H2_PHDR_FND_HOST)
+ host_cnt++;
+ /* skip duplicates, including real host from :authority */
+ if (fields & H2_PHDR_FND_HOST) {
+ /* check hardening, don't count :authority as a dup */
+ if (host_cnt > 1 && http_harden(HTTP_HRD_REJ_DUP_HOST_HDR))
+ goto fail;
continue;
+ }
fields |= H2_PHDR_FND_HOST;
if (http_authority_has_forbidden_char(list[idx].v))
struct ist meth = IST_NULL, path = IST_NULL;
struct ist scheme = IST_NULL, authority = IST_NULL;
struct ist uri;
+ int host_cnt = 0;
int hdr_idx, ret;
int cookie = -1, last_cookie = -1, i;
int relaxed = !!(h3c->qcc->proxy->options2 & PR_O2_REQBUG_OK);
if (isteq(list[hdr_idx].n, ist("host"))) {
struct ist prev_auth = authority;
+ host_cnt++;
if (http_authority_has_forbidden_char(list[hdr_idx].v) ||
h3_set_authority(qcs, &authority, list[hdr_idx].v)) {
h3s->err = H3_ERR_MESSAGE_ERROR;
if (isttest(prev_auth)) {
/* skip duplicate Host header */
+ /* TODO: need to check if it matches the previous one */
+ /* check hardening, but don't count :authority as a dup */
+ if (host_cnt > 1 && http_harden(HTTP_HRD_REJ_DUP_HOST_HDR)) {
+ h3s->err = H3_ERR_MESSAGE_ERROR;
+ qcc_report_glitch(h3c->qcc, 1);
+ len = -1;
+ goto out;
+ }
+
++hdr_idx;
continue;
}
/* list of known HTTP hardening options */
const struct http_hardening_kw http_hardening_kws[] = {
/* insert new hardening options below this line */
+ { "reject-duplicate-host-header", HTTP_HRD_REJ_DUP_HOST_HDR, HTTP_DIR_REQ },
/* insert new hardening options above this line */
{ "all", HTTP_HRD_ALL, HTTP_DIR_BOTH },
{ NULL, 0 }