Browse Source

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.
Loïc Hoguin 5 years ago
parent
commit
6ad842a742
3 changed files with 10 additions and 8 deletions
  1. 3 1
      doc/src/manual/cowboy_http2.asciidoc
  2. 1 1
      src/cowboy_http2.erl
  3. 6 6
      test/security_SUITE.erl

+ 3 - 1
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
 Note that actual frame sizes may be lower than the limit when
 there is not enough space left in the flow control window.
 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
 Maximum frame rate allowed per connection. The rate is expressed
 as a tuple `{NumFrames, TimeMs}` indicating how many frames are
 as a tuple `{NumFrames, TimeMs}` indicating how many frames are
@@ -236,6 +236,8 @@ too many `WINDOW_UPDATE` frames.
 == Changelog
 == Changelog
 
 
 * *2.8*: The `active_n` option was added.
 * *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`,
 * *2.7*: Add the options `connection_window_margin_size`,
          `connection_window_update_threshold`,
          `connection_window_update_threshold`,
          `max_connection_window_size`, `max_stream_window_size`,
          `max_connection_window_size`, `max_stream_window_size`,

+ 1 - 1
src/cowboy_http2.erl

@@ -171,7 +171,7 @@ init(Parent, Ref, Socket, Transport, ProxyHeader, Opts, Peer, Sock, Cert, Buffer
 	end.
 	end.
 
 
 init_rate_limiting(State=#state{opts=Opts}) ->
 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}),
 	{ResetRateNum, ResetRatePeriod} = maps:get(max_reset_stream_rate, Opts, {10, 10000}),
 	CurrentTime = erlang:monotonic_time(millisecond),
 	CurrentTime = erlang:monotonic_time(millisecond),
 	State#state{
 	State#state{

+ 6 - 6
test/security_SUITE.erl

@@ -116,7 +116,7 @@ http2_empty_frame_flooding_data(Config) ->
 		{<<":path">>, <<"/echo/read_body">>}
 		{<<":path">>, <<"/echo/read_body">>}
 	]),
 	]),
 	ok = gen_tcp:send(Socket, cow_http2:headers(1, nofin, HeadersBlock)),
 	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.
 	%% When Cowboy detects a flood it must close the connection.
 	%% We skip WINDOW_UPDATE frames sent when Cowboy starts to read the body.
 	%% We skip WINDOW_UPDATE frames sent when Cowboy starts to read the body.
 	case gen_tcp:recv(Socket, 43, 6000) of
 	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),
 	{ok, Socket} = rfc7540_SUITE:do_handshake(Config),
 	%% Send many empty HEADERS/CONTINUATION frames before the headers.
 	%% Send many empty HEADERS/CONTINUATION frames before the headers.
 	ok = gen_tcp:send(Socket, <<0:24, 1:8, 0:9, 1:31>>),
 	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([
 	{HeadersBlock, _} = cow_hpack:encode([
 		{<<":method">>, <<"POST">>},
 		{<<":method">>, <<"POST">>},
 		{<<":scheme">>, <<"http">>},
 		{<<":scheme">>, <<"http">>},
@@ -181,7 +181,7 @@ http2_ping_flood(Config) ->
 	doc("Confirm that Cowboy detects PING floods. (CVE-2019-9512)"),
 	doc("Confirm that Cowboy detects PING floods. (CVE-2019-9512)"),
 	{ok, Socket} = rfc7540_SUITE:do_handshake(Config),
 	{ok, Socket} = rfc7540_SUITE:do_handshake(Config),
 	%% Flood the server with PING frames.
 	%% 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.
 	%% Receive a number of PING ACK frames in return, following by the closing of the connection.
 	try
 	try
 		[case gen_tcp:recv(Socket, 17, 6000) of
 		[case gen_tcp:recv(Socket, 17, 6000) of
@@ -190,7 +190,7 @@ http2_ping_flood(Config) ->
 			%% We also accept the connection being closed immediately,
 			%% We also accept the connection being closed immediately,
 			%% which may happen because we send the GOAWAY right before closing.
 			%% which may happen because we send the GOAWAY right before closing.
 			{error, closed} -> throw(goaway)
 			{error, closed} -> throw(goaway)
-		end || _ <- lists:seq(1, 2000)],
+		end || _ <- lists:seq(1, 20000)],
 		error(flood_successful)
 		error(flood_successful)
 	catch throw:goaway ->
 	catch throw:goaway ->
 		ok
 		ok
@@ -231,7 +231,7 @@ http2_settings_flood(Config) ->
 	doc("Confirm that Cowboy detects SETTINGS floods. (CVE-2019-9515)"),
 	doc("Confirm that Cowboy detects SETTINGS floods. (CVE-2019-9515)"),
 	{ok, Socket} = rfc7540_SUITE:do_handshake(Config),
 	{ok, Socket} = rfc7540_SUITE:do_handshake(Config),
 	%% Flood the server with empty SETTINGS frames.
 	%% 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.
 	%% Receive a number of SETTINGS ACK frames in return, following by the closing of the connection.
 	try
 	try
 		[case gen_tcp:recv(Socket, 9, 6000) of
 		[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.
 			%% which may happen because we send the GOAWAY right before closing.
 			{error, closed} ->
 			{error, closed} ->
 				throw(goaway)
 				throw(goaway)
-		end || _ <- lists:seq(1, 2000)],
+		end || _ <- lists:seq(1, 20000)],
 		error(flood_successful)
 		error(flood_successful)
 	catch throw:goaway ->
 	catch throw:goaway ->
 		ok
 		ok