diff --git a/lib/inets/doc/guides/hardening.md b/lib/inets/doc/guides/hardening.md index b99e44fe4a0f..aa6ecd63e37c 100644 --- a/lib/inets/doc/guides/hardening.md +++ b/lib/inets/doc/guides/hardening.md @@ -229,22 +229,22 @@ or ### Request Size Limits -Several size limits default to `nolimit`, which allows arbitrarily large +Before OTP 30 several size limits default to `nolimit`, which allows arbitrarily large requests that can exhaust memory. Set explicit limits: ```erlang -[{max_uri_size, 8192}, %% 8 KB URI limit +[{max_uri_size, 8192}, %% 8 KB URI limit (default since OTP 30) {max_header_size, 10240}, %% 10 KB (already the default) {max_body_size, 10_485_760}, %% 10 MB body limit {max_content_length, 10_485_760}] %% 10 MB Content-Length check ``` -- **[`max_uri_size`](`m:httpd#prop_max_uri`)** - Maximum URI length in bytes. Default: `nolimit`. +- **[`max_uri_size`](`m:httpd#prop_max_uri`)** - Maximum URI length in bytes. Default: `8192` (8 KB). - **[`max_header_size`](`m:httpd#prop_max_header_size`)** - Maximum total header size. Default: `10240` (10 KB). - **[`max_body_size`](`m:httpd#prop_max_body_size`)** - Maximum received body size during parsing. Default: - `nolimit`. + `100_000_000` (100 MB). - **[`max_content_length`](`m:httpd#prop_max_content_length`)** - Rejects requests whose `Content-Length` header exceeds this value with a 413 response, before reading the body. Default: @@ -253,7 +253,7 @@ requests that can exhaust memory. Set explicit limits: - **[`max_client_body_chunk`](`m:httpd#max_client_body_chunk`)** - When handling large PUT or POST bodies via `mod_esi`, setting this option enforces chunked delivery to the ESI callback. This prevents the server from buffering the entire request body - in memory, which could be exploited to cause memory exhaustion. + in memory, which could be exploited to cause memory exhaustion. Default: `nolimit`. > #### Note {: .info } > diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl index d387f0a18147..d718f7299c77 100644 --- a/lib/inets/src/http_lib/http_internal.hrl +++ b/lib/inets/src/http_lib/http_internal.hrl @@ -26,12 +26,12 @@ -include_lib("inets/src/inets_app/inets_internal.hrl"). --define(HTTP_MAX_BODY_SIZE, nolimit). +-define(HTTP_MAX_BODY_SIZE, ?HTTP_MAX_CONTENT_LENGTH). %% 100 MB, same as max-content length -define(HTTP_MAX_HEADER_SIZE, 10240). --define(HTTP_MAX_URI_SIZE, nolimit). +-define(HTTP_MAX_URI_SIZE, 8192). -define(HTTP_MAX_VERSION_STRING, 8). -define(HTTP_MAX_METHOD_STRING, 20). --define(HTTP_MAX_CONTENT_LENGTH, 100000000). +-define(HTTP_MAX_CONTENT_LENGTH, 100000000). %% 100 MB -define(DATA_20MB, <<0:16#A000000>>). diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index e24d898ad7a7..c4d458e8cf1d 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -172,7 +172,8 @@ property list. client before closing the connection. Default is `150`. - [](){: #prop_max_body_size } **`{max_body_size, integer()}`** - Limits the size of the message body of an HTTP request. Default is no limit. + Limits the size of the message body of an HTTP request. Default is `100000000` (100 + MB). - [](){: #prop_max_clients } **`{max_clients, integer()}`** Limits the number of simultaneous requests that can be supported. Default is @@ -187,7 +188,7 @@ property list. MB). - [](){: #prop_max_uri } **`{max_uri_size, integer()}`** - Limits the size of the HTTP request URI. Default is no limit. + Limits the size of the HTTP request URI. Default is `8192` (8 KB). - [](){: #prop_max_keep_alive_req } **`{max_keep_alive_request, integer()}`** The number of requests that a client can do on one connection. When the server diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index f16e75587759..e87a8a5b3710 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -197,6 +197,12 @@ validate_config_params([{max_content_length, Value} | Rest]) validate_config_params([{max_content_length, Value} | _]) -> throw({max_content_length, Value}); +validate_config_params([{max_uri_size, Value} | Rest]) + when is_integer(Value) andalso (Value > 0) -> + validate_config_params(Rest); +validate_config_params([{max_uri_size, Value} | _]) -> + throw({max_uri_size, Value}); + validate_config_params([{server_name, Value} | Rest]) when is_list(Value) -> validate_config_params(Rest); diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index 9d18bfce0ee1..b1658b2b3031 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -148,8 +148,7 @@ parse_method(_, _, _, Max, _, _) -> %% will be able to handle it. {error, {size_error, Max, 413, "Method unreasonably long"}, default_version()}. -parse_uri(_, _, Current, MaxURI, _, _) - when (Current > MaxURI) andalso (MaxURI =/= nolimit) -> +parse_uri(_, _, Current, MaxURI, _, _) when Current > MaxURI -> %% We do not know the version of the client as it comes after the %% uri send the lowest version in the response so that the client %% will be able to handle it. @@ -180,8 +179,7 @@ parse_version(<>, Version, Current, Max, Options, Result) w parse_version(_, _, _, Max,_,_) -> {error, {size_error, Max, 413, "Version string unreasonably long"}, default_version()}. -parse_headers(_, _, _, Current, Max, _, Result) - when Max =/= nolimit andalso Current > Max -> +parse_headers(_, _, _, Current, Max, _, Result) when Current > Max -> HttpVersion = lists:nth(3, lists:reverse(Result)), {error, {size_error, Max, 413, "Headers unreasonably long"}, HttpVersion}; diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index 2c6c5be92e47..8efa047637fb 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -536,7 +536,7 @@ handle_body(#state{headers = Headers, body = Body, _ -> Length = list_to_integer(Headers#http_request_h.'content-length'), MaxChunk = max_client_body_chunk(ConfigDB), - case Length =< MaxBodySize orelse MaxBodySize == nolimit of + case Length =< MaxBodySize of true -> case httpd_request:body_chunk_first(Body, Length, MaxChunk) of %% This is the case that the we need more data to complete @@ -572,7 +572,7 @@ handle_expect(#state{headers = Headers, mod = MaxBodySize) -> Length = list_to_integer(Headers#http_request_h.'content-length'), case expect(Headers, ModData#mod.http_version, ConfigDB) of - continue when (MaxBodySize > Length) orelse (MaxBodySize =:= nolimit) -> + continue when MaxBodySize > Length -> httpd_response:send_status(ModData, 100, ""), ok; continue when MaxBodySize < Length -> @@ -762,7 +762,7 @@ max_uri_size(ConfigDB) -> httpd_util:lookup(ConfigDB, max_uri_size, ?HTTP_MAX_URI_SIZE). max_body_size(ConfigDB) -> - httpd_util:lookup(ConfigDB, max_body_size, nolimit). + httpd_util:lookup(ConfigDB, max_body_size, ?HTTP_MAX_BODY_SIZE). max_keep_alive_request(ConfigDB) -> httpd_util:lookup(ConfigDB, max_keep_alive_request, infinity).