![使用 nftables 创建动态黑名单](https://linux22.com/image/171693/%E4%BD%BF%E7%94%A8%20nftables%20%E5%88%9B%E5%BB%BA%E5%8A%A8%E6%80%81%E9%BB%91%E5%90%8D%E5%8D%95.png)
我想用 nftables 创建一个动态黑名单。在嵌入式设备上的 0.8.3 版本下,我使用 nft list 规则集创建一个如下所示的规则集:
table inet filter {
set blackhole {
type ipv4_addr
size 65536
flags timeout
}
chain input {
type filter hook input priority 0; policy drop;
ct state invalid drop
ct state established,related accept
iif "lo" accept
ip6 nexthdr 58 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept
ip protocol icmp icmp type { echo-reply, destination-unreachable, echo-request, router-advertisement, router-solicitation, time-exceeded, parameter-problem } accept
ip saddr @blackhole counter packets 0 bytes 0 drop
tcp flags syn tcp dport ssh meter flood { ip saddr timeout 1m limit rate over 10/second burst 5 packets} set add ip saddr timeout 1m @blackhole drop
tcp dport ssh accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
对我来说这只是一个临时解决方案。我想用官方的例子联机帮助页用于动态黑名单。如果我使用联机帮助页中的官方示例,我的 nftables 文件如下所示:
table inet filter {
set blackhole{
type ipv4_addr
flags timeout
size 65536
}
chain input {
type filter hook input priority 0; policy drop;
# drop invalid connections
ct state invalid drop
# accept traffic originating from us
ct state established,related accept
# accept any localhost traffic
iif lo accept
# accept ICMP
ip6 nexthdr 58 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept
ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem, echo-request, echo-reply } accept
# accept SSH (port 22)
ip saddr @blackhole counter drop
tcp flags syn tcp dport ssh meter flood { ip saddr timeout 10s limit rate over 10/second} add @blackhole { ip saddr timeout 1m } drop
tcp dport 22 accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
但是当我使用 nft -f myfile 在 0.8.3 版本上加载此 nftables 文件时,出现此错误:
Error: syntax error, unexpected add, expecting newline or semicolon
tcp flags syn tcp dport ssh meter flood { ip saddr timeout 10s limit rate over 10/second} add @blackhole { ip saddr timeout 1m } drop
我不知道为什么会这样,但根据维基百科它应该可以从版本 0.8.1 和内核 4.3 开始工作。
我的版本是0.8.3,内核是4.19.94。
我已经在 Debian Buster 下测试了 0.9.0 版官方手册页中的规则集。手册页中的规则集在 Debian 上运行良好,但 IP 仅被阻止一次。
在这个例子中,我想创建一个防火墙规则,如果对我的设备发起暴力攻击,该规则会阻止 ssh 端口上的 IP 地址。但我想封锁IP,例如5分钟。在此之后,应该可以从攻击者的 IP 再次连接到设备。如果他再次进行暴力破解,则应再次封锁 ip 5 分钟,依此类推。如果 nftables 可以的话,我想避免为我的嵌入式设备使用其他软件,例如 sshguard 或fail2ban。
我希望任何人都可以帮助我。谢谢!
答案1
这hydra
工具同时多次连接到 SSH 服务器。在OP的情况下(评论:)hydra -l <username> -P </path/to/passwordlist.txt> -I -t 6 ssh://<ip-address>
它将使用 6 个并发线程连接。
根据服务器设置,一个连接通常可以尝试 5 或 6 个密码,并且需要大约 10 秒的时间才会被 SSH 服务器拒绝,因此我无法看出 10 的速率如何联系每秒的尝试次数可能会被超出(但事实就是如此)。这可能意味着触发的是在不到 1/2 秒内完成了 5 次以上的连接尝试。我不太相信 的准确性10/s
,但可以假设它发生在这里。
版本和语法问题
不适用于版本 0.8.1 或 0.8.3 的语法是出现在的较新语法这次提交:
src:重新访问语法以更新数据包路径中的集和映射
对于集合,我们允许这样:
nft add rule x y ip protocol tcp update @y { ip saddr}
[...]
它已被承诺后版本 0.8.3 仅适用于 nftables >= 0.8.4
当前的 wiki 修订版为从数据包路径更新集,在同一页面中,仍然显示以前语法的命令
% nft add rule filter input set add ip saddr @myset
[...]
并使用新语法显示结果:
[...]
add @myset { ip saddr }
[...]
某些 wiki 页面或最新的联机帮助页可能不适用于较旧的 nftables 版本。
无论如何,如果使用内核 4.19 运行,nftables>= 0.9.0 应该是首选以获得附加功能。例如,它可以在Debian 10或在Debian 9 向后移植。
黑名单应该在状态接受规则之前完成
一旦 IP 被添加到黑名单中,这并不会阻止已建立的连接继续、不受阻碍且不被考虑,直到它们被 SSH 服务器本身断开。那是因为之前有通常存在的短路规则:
# accept traffic originating from us ct state established,related accept
此评论具有误导性:事实并非如此接受来自我们的流量但任何已经在进行的交通。这是短路规则。它的作用是通过仅解析新连接的所有规则来处理有状态连接:此规则之后的任何规则都适用于新连接。一旦连接被接受,它们的各个数据包将保持被接受状态,直到连接结束。
对于具体的黑名单处理情况,需要将具体的黑名单规则或者其中的一部分放置在该短路规则之前,以便能够立即生效。在OP的情况下是:
ip saddr @blackhole counter drop
应将其移至ct state established,related accept
规则之前。
现在,一旦攻击者被添加到黑名单中,其他正在进行的连接将无法获得一些剩余的免费尝试来猜测密码:它们将立即挂起。
如果有黑名单,请考虑白名单
附带说明一下,便宜的iif lo accept
规则本身可以作为优化和被列入白名单之前移动:所有(甚至是长期存在的)本地建立的连接现在也将在滥用情况下被列入黑名单(例如:来自 127.0.0.1) 。考虑在规则之前添加各种白名单规则@blackhole
。
可选择更快地警告应用程序
为了防止来自服务器的持续回复到达黑名单 IP(特别是对于 UDP 流量,对于 TCP 没有多大用处,包括 SSH),daddr
还可以在inet filter output
链中添加使用的等效规则,并使用拒绝更快地通知试图回复的本地进程。发出他们应该中止的信号:
ip daddr @blackhole counter reject
集合之间的区别add
和update
应用于集合上的区别
现在有了这样的设置,即使正在进行的连接立即停止,攻击者也能够继续尝试并在 100 万年后获得一个新的短窗口,这不是最佳的。
条目必须是更新输入@blackhole ... drop
规则中的d。update
如果条目已经存在,则会刷新计时器,而add
不会执行任何操作。这将继续阻止任何进一步(不成功)连接到 SSH 服务器的尝试,直到攻击者放弃,打开的窗口为零。 (我上面添加的输出规则不应该改变,这不是攻击者的行为):
代替:
ip saddr @blackhole counter drop
与(仍然保留旧语法):
ip saddr @blackhole counter set update ip saddr timeout 1m @blackhole drop
它甚至应该移到ct state invalid
规则之前,否则如果攻击者尝试无效的数据包(例如,TCP 数据包不是已知连接的一部分,例如来自已忘记的连接的迟到的 RST),则该集将不会更新,而它本可以更新。
限制最大建立连接数
需要内核 >= 4.18 且 nftables >= 0.9.0,因此无法使用 OP 的当前配置来完成。
攻击者可能会发现它不能一次连接太多次,但仍然可以无限制地不断添加新连接,只要连接速度不要太快。
A并发连接数限制(与 iptables 一样可用connlimit
) 还可以添加其他计量规则:
tcp flags syn tcp dport 22 meter toomanyestablished { ip saddr ct count over 3 } reject with tcp reset
将允许任何给定的 IP 地址仅建立 3 个 SSH 连接。
或者,同时也触发 @blackhole 集(这次使用更新的语法):
tcp flags syn tcp dport 22 meter toomanyestablished { ip saddr ct count over 3 } add @blackhole { ip saddr timeout 1m } drop
在 OP 的情况下,这甚至应该在之前的计量规则之前触发。请谨慎使用,避免合法用户受到影响(但请参阅 openssh 的ControlMaster
选项)。
IPv4 和 IPv6
由于没有通用的 IPv4+IPv6 集地址类型,因此处理 IPv4 的所有规则(只要有 2 个字母的单词ip
)可能应该复制到ip6
其中包含并在 IPv6 集上工作的镜像规则中。