From 6ad842a742915066d319f307a0f60cd8df15598b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Sun, 29 Mar 2020 13:51:21 +0200 Subject: Increase the default max_received_frame_rate Allow 10000 frames every 10 seconds instead of just 1000, as the limit was too quickly reached in some deployments. --- doc/src/manual/cowboy_http2.asciidoc | 4 +++- src/cowboy_http2.erl | 2 +- test/security_SUITE.erl | 12 ++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/src/manual/cowboy_http2.asciidoc b/doc/src/manual/cowboy_http2.asciidoc index b8a9258..e803f56 100644 --- a/doc/src/manual/cowboy_http2.asciidoc +++ b/doc/src/manual/cowboy_http2.asciidoc @@ -161,7 +161,7 @@ following the client's advertised maximum. Note that actual frame sizes may be lower than the limit when there is not enough space left in the flow control window. -max_received_frame_rate ({1000, 10000}):: +max_received_frame_rate ({10000, 10000}):: Maximum frame rate allowed per connection. The rate is expressed as a tuple `{NumFrames, TimeMs}` indicating how many frames are @@ -236,6 +236,8 @@ too many `WINDOW_UPDATE` frames. == Changelog * *2.8*: The `active_n` option was added. +* *2.8*: The `max_received_frame_rate` default value has + been multiplied by 10 as the default was too low. * *2.7*: Add the options `connection_window_margin_size`, `connection_window_update_threshold`, `max_connection_window_size`, `max_stream_window_size`, diff --git a/src/cowboy_http2.erl b/src/cowboy_http2.erl index 03ec9f8..5224737 100644 --- a/src/cowboy_http2.erl +++ b/src/cowboy_http2.erl @@ -171,7 +171,7 @@ init(Parent, Ref, Socket, Transport, ProxyHeader, Opts, Peer, Sock, Cert, Buffer end. init_rate_limiting(State=#state{opts=Opts}) -> - {FrameRateNum, FrameRatePeriod} = maps:get(max_received_frame_rate, Opts, {1000, 10000}), + {FrameRateNum, FrameRatePeriod} = maps:get(max_received_frame_rate, Opts, {10000, 10000}), {ResetRateNum, ResetRatePeriod} = maps:get(max_reset_stream_rate, Opts, {10, 10000}), CurrentTime = erlang:monotonic_time(millisecond), State#state{ diff --git a/test/security_SUITE.erl b/test/security_SUITE.erl index 5aeded9..0e72d74 100644 --- a/test/security_SUITE.erl +++ b/test/security_SUITE.erl @@ -116,7 +116,7 @@ http2_empty_frame_flooding_data(Config) -> {<<":path">>, <<"/echo/read_body">>} ]), ok = gen_tcp:send(Socket, cow_http2:headers(1, nofin, HeadersBlock)), - _ = [gen_tcp:send(Socket, cow_http2:data(1, nofin, <<>>)) || _ <- lists:seq(1, 2000)], + _ = [gen_tcp:send(Socket, cow_http2:data(1, nofin, <<>>)) || _ <- lists:seq(1, 20000)], %% When Cowboy detects a flood it must close the connection. %% We skip WINDOW_UPDATE frames sent when Cowboy starts to read the body. case gen_tcp:recv(Socket, 43, 6000) of @@ -133,7 +133,7 @@ http2_empty_frame_flooding_headers_continuation(Config) -> {ok, Socket} = rfc7540_SUITE:do_handshake(Config), %% Send many empty HEADERS/CONTINUATION frames before the headers. ok = gen_tcp:send(Socket, <<0:24, 1:8, 0:9, 1:31>>), - _ = [gen_tcp:send(Socket, <<0:24, 9:8, 0:9, 1:31>>) || _ <- lists:seq(1, 2000)], + _ = [gen_tcp:send(Socket, <<0:24, 9:8, 0:9, 1:31>>) || _ <- lists:seq(1, 20000)], {HeadersBlock, _} = cow_hpack:encode([ {<<":method">>, <<"POST">>}, {<<":scheme">>, <<"http">>}, @@ -181,7 +181,7 @@ http2_ping_flood(Config) -> doc("Confirm that Cowboy detects PING floods. (CVE-2019-9512)"), {ok, Socket} = rfc7540_SUITE:do_handshake(Config), %% Flood the server with PING frames. - _ = [gen_tcp:send(Socket, cow_http2:ping(0)) || _ <- lists:seq(1, 2000)], + _ = [gen_tcp:send(Socket, cow_http2:ping(0)) || _ <- lists:seq(1, 20000)], %% Receive a number of PING ACK frames in return, following by the closing of the connection. try [case gen_tcp:recv(Socket, 17, 6000) of @@ -190,7 +190,7 @@ http2_ping_flood(Config) -> %% We also accept the connection being closed immediately, %% which may happen because we send the GOAWAY right before closing. {error, closed} -> throw(goaway) - end || _ <- lists:seq(1, 2000)], + end || _ <- lists:seq(1, 20000)], error(flood_successful) catch throw:goaway -> ok @@ -231,7 +231,7 @@ http2_settings_flood(Config) -> doc("Confirm that Cowboy detects SETTINGS floods. (CVE-2019-9515)"), {ok, Socket} = rfc7540_SUITE:do_handshake(Config), %% Flood the server with empty SETTINGS frames. - _ = [gen_tcp:send(Socket, cow_http2:settings(#{})) || _ <- lists:seq(1, 2000)], + _ = [gen_tcp:send(Socket, cow_http2:settings(#{})) || _ <- lists:seq(1, 20000)], %% Receive a number of SETTINGS ACK frames in return, following by the closing of the connection. try [case gen_tcp:recv(Socket, 9, 6000) of @@ -243,7 +243,7 @@ http2_settings_flood(Config) -> %% which may happen because we send the GOAWAY right before closing. {error, closed} -> throw(goaway) - end || _ <- lists:seq(1, 2000)], + end || _ <- lists:seq(1, 20000)], error(flood_successful) catch throw:goaway -> ok -- cgit v1.2.3