aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2021-01-18 13:43:36 +0300
committerRoman Arutyunyan <arut@nginx.com>2021-01-18 13:43:36 +0300
commit7bac596afb31344cf40c93d8ae1ce87d2b6c76c1 (patch)
tree746d3691dab8f3b5f9061b0867849611a36350f9
parent88f6b969e6963d5771b708adeb43d1c8de14db6e (diff)
downloadnginx-7bac596afb31344cf40c93d8ae1ce87d2b6c76c1.tar.gz
nginx-7bac596afb31344cf40c93d8ae1ce87d2b6c76c1.zip
HTTP/3: client header validation.
A header with the name containing null, CR, LF, colon or uppercase characters, is now considered an error. A header with the value containing null, CR or LF, is also considered an error. Also, header is considered invalid unless its name only contains lowercase characters, digits, minus and optionally underscore. Such header can be optionally ignored.
-rw-r--r--src/http/v3/ngx_http_v3_request.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c
index 59a8889bf..fb1626718 100644
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -13,6 +13,8 @@
static void ngx_http_v3_process_request(ngx_event_t *rev);
static ngx_int_t ngx_http_v3_process_header(ngx_http_request_t *r,
ngx_str_t *name, ngx_str_t *value);
+static ngx_int_t ngx_http_v3_validate_header(ngx_http_request_t *r,
+ ngx_str_t *name, ngx_str_t *value);
static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
ngx_str_t *name, ngx_str_t *value);
static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r);
@@ -260,8 +262,25 @@ ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name,
{
ngx_table_elt_t *h;
ngx_http_header_t *hh;
+ ngx_http_core_srv_conf_t *cscf;
ngx_http_core_main_conf_t *cmcf;
+ if (ngx_http_v3_validate_header(r, name, value) != NGX_OK) {
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return NGX_ERROR;
+ }
+
+ if (r->invalid_header) {
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ if (cscf->ignore_invalid_headers) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid header: \"%V\"", name);
+
+ return NGX_OK;
+ }
+ }
+
if (name->len && name->data[0] == ':') {
return ngx_http_v3_process_pseudo_header(r, name, value);
}
@@ -297,6 +316,57 @@ ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name,
static ngx_int_t
+ngx_http_v3_validate_header(ngx_http_request_t *r, ngx_str_t *name,
+ ngx_str_t *value)
+{
+ u_char ch;
+ ngx_uint_t i;
+ ngx_http_core_srv_conf_t *cscf;
+
+ r->invalid_header = 0;
+
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ for (i = (name->data[0] == ':'); i != name->len; i++) {
+ ch = name->data[i];
+
+ if ((ch >= 'a' && ch <= 'z')
+ || (ch == '-')
+ || (ch >= '0' && ch <= '9')
+ || (ch == '_' && cscf->underscores_in_headers))
+ {
+ continue;
+ }
+
+ if (ch == '\0' || ch == LF || ch == CR || ch == ':'
+ || (ch >= 'A' && ch <= 'Z'))
+ {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid header name: \"%V\"", name);
+
+ return NGX_ERROR;
+ }
+
+ r->invalid_header = 1;
+ }
+
+ for (i = 0; i != value->len; i++) {
+ ch = value->data[i];
+
+ if (ch == '\0' || ch == LF || ch == CR) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent header \"%V\" with "
+ "invalid value: \"%V\"", name, value);
+
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
ngx_str_t *value)
{