]> git.kaiwu.me - nginx.git/commitdiff
Range filter: reasonable limit on multiple ranges.
authorSergey Kandaurov <pluknet@nginx.com>
Tue, 13 Jan 2026 12:51:07 +0000 (16:51 +0400)
committerSergey Kandaurov <s.kandaurov@f5.com>
Wed, 21 Jan 2026 16:39:00 +0000 (20:39 +0400)
A total response length with multiple ranges can be larger than the
source response size due to multipart boundary headers.  This change
extends max ranges limit imposed in c2c3e3105 (1.1.2) by accounting
boundary headers.  Notably, this covers suspicious requests with a
lot of small ranges that have an increased processing overhead and
are susceptible to range based amplification attacks.

The limit disables ranges as long as a total response length comes
close to the source size, additionally penalizing small size ranges
on a large source size where a processing overhead prevails, while
leaving a room for more ranges on a small source size, such that it
should not affect well-behaving applications.  The limit can be
altered with the "max_ranges" directive.

Closes #988 on GitHub.

src/http/modules/ngx_http_range_filter_module.c

index 27d1875c8e0b0abc9253e791a63fbe178e2df6cb..fec3642cf9dcf88eff5ac78ba5940ce171074be3 100644 (file)
@@ -273,7 +273,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
     u_char                       *p;
     off_t                         start, end, size, content_length, cutoff,
                                   cutlim;
-    ngx_uint_t                    suffix;
+    ngx_uint_t                    suffix, max_ranges;
     ngx_http_range_t             *range;
     ngx_http_range_filter_ctx_t  *mctx;
 
@@ -294,6 +294,8 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
 
     p = r->headers_in.range->value.data + 6;
     size = 0;
+    max_ranges = ranges;
+
     content_length = r->headers_out.content_length_n;
 
     cutoff = NGX_MAX_OFF_T_VALUE / 10;
@@ -401,10 +403,23 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
         return NGX_HTTP_RANGE_NOT_SATISFIABLE;
     }
 
+    if (ctx->ranges.nelts == 1) {
+        return NGX_OK;
+    }
+
     if (size > content_length) {
         return NGX_DECLINED;
     }
 
+    if (max_ranges == NGX_MAX_INT32_VALUE) {
+        size += ctx->ranges.nelts * 256;
+        content_length += 4096;
+
+        if (size > content_length) {
+            return NGX_DECLINED;
+        }
+    }
+
     return NGX_OK;
 }