[PATCH 08 of 10] Request body: limited chunk extensions and trailer headers
Maxim Dounin
mdounin at mdounin.ru
Fri Mar 15 18:14:22 UTC 2024
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1710526256 -10800
# Fri Mar 15 21:10:56 2024 +0300
# Node ID ece1df3184a22241682cb5ee8402dbb79015b204
# Parent 9f3e833ac0e10401d2da60953723d160c1bf4b5e
Request body: limited chunk extensions and trailer headers.
Previously, arbitrary amounts of chunk extensions and trailer headers were
accepted and skipped. Despite being under limit_conn / limit_req limits
(if configured), this can be a DoS vector, so it is now limited by the
client_max_body_size limit.
Reported by Bartek Nowotarski.
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -65,6 +65,7 @@ struct ngx_http_chunked_s {
ngx_uint_t state;
off_t size;
off_t length;
+ off_t skipped;
};
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -2257,6 +2257,9 @@ ngx_http_parse_chunked(ngx_http_request_
break;
case LF:
state = sw_chunk_data;
+ break;
+ default:
+ ctx->skipped++;
}
break;
@@ -2298,6 +2301,9 @@ ngx_http_parse_chunked(ngx_http_request_
break;
case LF:
state = sw_trailer;
+ break;
+ default:
+ ctx->skipped++;
}
break;
@@ -2333,6 +2339,9 @@ ngx_http_parse_chunked(ngx_http_request_
break;
case LF:
state = sw_trailer;
+ break;
+ default:
+ ctx->skipped++;
}
break;
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -1141,6 +1141,17 @@ ngx_http_request_body_chunked_filter(ngx
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->client_max_body_size
+ && clcf->client_max_body_size < rb->chunked->skipped)
+ {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "client sent too many chunk extensions");
+
+ r->lingering_close = 1;
+
+ return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
+ if (clcf->client_max_body_size
&& clcf->client_max_body_size
- r->headers_in.content_length_n < rb->chunked->size)
{
@@ -1241,6 +1252,20 @@ ngx_http_request_body_chunked_filter(ngx
if (rc == NGX_AGAIN) {
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->client_max_body_size
+ && clcf->client_max_body_size < rb->chunked->skipped)
+ {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "client sent too many chunk extensions "
+ "or trailer headers");
+
+ r->lingering_close = 1;
+
+ return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
/* set rb->rest, amount of data we want to see next time */
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
More information about the nginx-devel
mailing list