我已经设置了速率限制来阻止对我的 ssh 服务器的暴力攻击。我使用以下 iptables 规则:
iptables -A INPUT -p tcp -m tcp --dport 22 -m hashlimit --hashlimit-upto 4/min
--hashlimit-burst 6 --hashlimit-mode srcip --hashlimit-name ssh
--hashlimit-htable-expire 60000 -m state --state NEW -j ACCEPT
iptables -A INPUT -m tcp -p tcp --dport 22 -m state --state NEW -j REJECT
当我打开一个 SSH 连接(例如通过 PuTTY),然后一分钟后尝试打开另一个连接(例如,传输文件)时,第二个连接有时会被拒绝,服务器没有响应如果我设法打开第二个 SSH 连接,然后尝试打开第三个连接,则会变得更加困难(很可能没有响应)。
我已经验证,当我禁用上述规则时,一切都正常。增加--hashlimit-upto
and/or--hashlimit-burst
有帮助,但不能完全解决问题——它只会降低发生这种情况的可能性。有时仍会发生拒绝,而如果我禁用 iptables 规则,这种情况就不会发生。
发生了什么?上面的 iptables 规则规定与新连接相关的 TCP 数据包应限制为每分钟 4 个。所以我应该可以轻松地每分钟打开 4 个连接。
答案1
(回答我自己的问题,为其他人留下记录。)
你的第一条规则是:
iptables -A INPUT -p tcp -m tcp --dport 22 -m hashlimit --hashlimit-upto 4/min
--hashlimit-burst 6 --hashlimit-mode srcip --hashlimit-name ssh
--hashlimit-htable-expire 60000 -m state --state NEW -j ACCEPT
并没有按照你的想法去做。当你说-m tcp
、-m hashlimit
和 时-m state
,你调用了三个 iptables 模块。你认为 hashlimit 只适用于满足规则中所有其他条件的数据包。但事实并非如此。相反,模块按照规则中给出的顺序执行. (据我所知,这个事实并不是直观明显的,也没有在任何地方明确记录。)
在上面的规则中,-m hashlimit
位于 之前-m state
。这意味着每个 TCP 数据包(不仅仅是一个新的包)将第一的被发送到 hashlimit 模块。Hashlimit 将计算此数据包,如果在限制范围内4/min
,它将被传递给-m state
。只有现在state
模块才能查看数据包并检查它是否代表新连接。
因此,在您的情况下,会发生以下情况:您打开第一个 SSH 连接,它会不时传输一些数据包。这些数据包不是“新”数据包,因此不会被丢弃(--state NEW
第二条规则中的条件不满足)。但是它们由 hashlimit 处理,并将计入你的4/min
限制。如果它们的速度足够快,它们就会用尽配额,如果您随后尝试打开另一个连接,则该连接的第一个数据包将超出配额,并且您的第一条规则将不匹配。
显而易见的解决方案是改变顺序:
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m hashlimit
--hashlimit-upto 4/min --hashlimit-burst 6 --hashlimit-mode srcip --hashlimit-name ssh
--hashlimit-htable-expire 60000 -j ACCEPT
总的来说,我认为一个好的经验法则是始终-m hashlimit
位于 iptables 规则的最后。