mirror of
https://github.com/seriyps/mtproto_proxy.git
synced 2026-05-13 08:46:46 +00:00
Replay attack mitigation
Storage of recently used 1st packets added. Connections with the same 1st packet are disallowed
This commit is contained in:
parent
07d397ce93
commit
0f4d180a06
6 changed files with 304 additions and 4 deletions
|
|
@ -2,6 +2,7 @@
|
|||
-module(mtp_test_client).
|
||||
|
||||
-export([connect/5,
|
||||
connect/6,
|
||||
send/2,
|
||||
recv_packet/2,
|
||||
recv_all/2,
|
||||
|
|
@ -16,13 +17,17 @@
|
|||
-type tcp_error() :: inet:posix() | closed. % | timeout.
|
||||
|
||||
connect(Host, Port, Secret, DcId, Protocol) ->
|
||||
Seed = crypto:strong_rand_bytes(58),
|
||||
connect(Host, Port, Seed, Secret, DcId, Protocol).
|
||||
|
||||
connect(Host, Port, Seed, Secret, DcId, Protocol) ->
|
||||
Opts = [{packet, raw},
|
||||
{mode, binary},
|
||||
{active, false},
|
||||
{buffer, 1024},
|
||||
{send_timeout, 5000}],
|
||||
{ok, Sock} = gen_tcp:connect(Host, Port, Opts, 1000),
|
||||
{Header, _, _, CryptoLayer} = mtp_obfuscated:client_create(Secret, Protocol, DcId),
|
||||
{Header, _, _, CryptoLayer} = mtp_obfuscated:client_create(Seed, Secret, Protocol, DcId),
|
||||
ok = gen_tcp:send(Sock, Header),
|
||||
PacketLayer = Protocol:new(),
|
||||
Codec = mtp_codec:new(mtp_obfuscated, CryptoLayer,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
packet_too_large_case/1,
|
||||
downstream_size_backpressure_case/1,
|
||||
downstream_qlen_backpressure_case/1,
|
||||
config_change_case/1
|
||||
config_change_case/1,
|
||||
replay_attack_case/1
|
||||
]).
|
||||
|
||||
-export([set_env/2,
|
||||
|
|
@ -308,6 +309,36 @@ config_change_case(Cfg) when is_list(Cfg) ->
|
|||
?assertEqual(PortsBefore, mtproto_proxy_app:running_ports()),
|
||||
ok.
|
||||
|
||||
|
||||
%% @doc test replay attack protection.
|
||||
%% Attempts to connect with the same 1st 64-byte packet should be rejected.
|
||||
replay_attack_case({pre, Cfg}) ->
|
||||
setup_single(?FUNCTION_NAME, 10000 + ?LINE, #{}, Cfg);
|
||||
replay_attack_case({post, Cfg}) ->
|
||||
stop_single(Cfg);
|
||||
replay_attack_case(Cfg) when is_list(Cfg) ->
|
||||
DcId = ?config(dc_id, Cfg),
|
||||
Host = ?config(mtp_host, Cfg),
|
||||
Port = ?config(mtp_port, Cfg),
|
||||
Secret = ?config(mtp_secret, Cfg),
|
||||
Seed = crypto:strong_rand_bytes(58),
|
||||
ErrCount = fun() ->
|
||||
mtp_test_metric:get_tags(
|
||||
count, [?APP, protocol_error, total], [replay_session_detected])
|
||||
end,
|
||||
?assertEqual(not_found, ErrCount()),
|
||||
Cli1 = mtp_test_client:connect(Host, Port, Seed, Secret, DcId, mtp_secure),
|
||||
_Cli1_1 = mtp_test_client:send(crypto:strong_rand_bytes(64), Cli1),
|
||||
?assertEqual(not_found, ErrCount()),
|
||||
Cli2 = mtp_test_client:connect(Host, Port, Seed, Secret, DcId, mtp_secure),
|
||||
?assertEqual(
|
||||
ok, mtp_test_metric:wait_for_value(
|
||||
count, [?APP, protocol_error, total], [replay_session_detected], 1, 5000),
|
||||
{mtp_session_storage:status(),
|
||||
sys:get_state(mtp_test_metric)}),
|
||||
?assertEqual(1, ErrCount()),
|
||||
?assertEqual({error, closed}, mtp_test_client:recv_packet(Cli2, 1000)).
|
||||
|
||||
%% TODO: send a lot, not read, and then close - assert connection IDs are cleaned up
|
||||
|
||||
%% Helpers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue