Restrict connection-specific headers in HTTP/2 and HTTP/3
Some checks are pending
buildbot / buildbot (push) Waiting to run

As per RFC 9113 and RFC 9114, any message containing such headers MUST be
treated as malformed.

As per RFC 9110, Section 7.6.1, the following headers are considered
connection-specific:

- Connection
- Proxy-Connection
- Keep-Alive
- TE
- Transfer-Encoding
- Upgrade

The only exception is the TE header field, which MAY be present in a
request header, but it MUST NOT contain any value other than "trailers".
This commit is contained in:
Roman Arutyunyan 2026-04-08 17:19:24 +04:00 committed by Roman Arutyunyan
parent 00979ba9d8
commit d3a76322cf
3 changed files with 98 additions and 0 deletions

View file

@ -26,6 +26,8 @@ static ngx_int_t ngx_http_process_host(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_proxy_connection(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
@ -82,6 +84,9 @@ ngx_http_header_t ngx_http_headers_in[] = {
{ ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),
ngx_http_process_connection },
{ ngx_string("Proxy-Connection"), 0,
ngx_http_process_proxy_connection },
{ ngx_string("If-Modified-Since"),
offsetof(ngx_http_headers_in_t, if_modified_since),
ngx_http_process_unique_header_line },
@ -1928,6 +1933,21 @@ ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
}
static ngx_int_t
ngx_http_process_proxy_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
if (r->http_version >= NGX_HTTP_VERSION_20) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent \"Proxy-Connection\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)

View file

@ -3820,6 +3820,45 @@ ngx_http_v2_run_request(ngx_http_request_t *r)
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
if (r->headers_in.connection) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Connection\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.keep_alive) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Keep-Alive\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.transfer_encoding) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Transfer-Encoding\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.upgrade) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Upgrade\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.te
&& (r->headers_in.te->value.len != 8
|| ngx_strncasecmp(r->headers_in.te->value.data,
(u_char *) "trailers", 8) != 0))
{
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent invalid \"TE\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.server.len == 0) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent neither \":authority\" nor \"Host\" header");

View file

@ -1021,6 +1021,45 @@ ngx_http_v3_process_request_header(ngx_http_request_t *r)
c = r->connection;
if (r->headers_in.connection) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Connection\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.keep_alive) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Keep-Alive\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.transfer_encoding) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Transfer-Encoding\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.upgrade) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Upgrade\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.te
&& (r->headers_in.te->value.len != 8
|| ngx_strncasecmp(r->headers_in.te->value.data,
(u_char *) "trailers", 8) != 0))
{
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent invalid \"TE\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
return NGX_ERROR;
}