30.6. Blacklistd

Blacklistd 是一个监听套接字的守护进程,用于接收来自其他守护进程的连接尝试失败或成功的通知。它常用于阻止开放端口上的过多连接尝试。一个最典型的例子是在互联网上运行的SSH会收到大量来自机器人或脚本的请求,试图猜测密码并获得访问权限。使用blacklistd,守护进程可以通知防火墙创建过滤规则,在多次尝试后,阻止来一来源的过量连接尝试。Blacklistd 最早是在 NetBSD 上开发的, 并在 7 版中出现。FreeBSD 11 从 NetBSD 中导入了 blacklistd。

本章介绍如何设置黑名单、配置它,并提供如何使用它的示例。读者应该熟悉基本的防火墙概念,如规则。有关详细信息,请参阅防火墙章节。示例中使用了 PF,但 FreeBSD 上提供的其他防火墙也应该能够使用黑名单。

30.6.1. 启用黑名单

blacklistd 的主要配置方法在 blacklistd.conf(5)。各种命令行选项也可以用来改变 blacklistd 的运行时行为。在重启期间的持久化配置应该存储在 /etc/blacklistd.conf中。要在系统启动时启用守护进程,请在/etc/rc.conf中添加blacklistd_enable行,像这样:

# sysrc blacklistd_enable=yes

手动启动服务,运行以下命令:

# service blacklistd start

30.6.2. 创建黑名单规则集

blacklistd 的规则在 blacklistd.conf(5)中详细介绍,每行一个条目。每个规则包含一个用空格或制表符分隔的元组。规则要么属于local,要么属于remote,分别适用于本机,blacklistd 外部源。

30.6.2.1. 本地规则

blacklistd.conf 中的本地规则类似这样:

[local]
ssh             stream  *       *               *       3       24h

遵循[local]部分的所有规则都被视为本地规则(这是默认的),适用于本地机器。当遇到[remote]部分时,所有遵循该部分的规则都将作为远程机器规则处理。

七个字段定义由制表符或空格分隔的规则。前四个字段标识应列入黑名单的流量。随后的三个字段定义了列入后列表的行为。通配符表示为星号( * ),匹配此字段中的任何内容。第一个字段定义位置。在本地规则中,这些是网络端口。 location字段的语法如下:

[address|interface][/mask][:port]

Adressses 可以指定为数字格式的 IPv4 或方括号内的 IPv6。也可以使用像em0这样的接口名称。

套接字段的类型由第二个字段定义。TCP套接字段的类型是stream,而UDP则表示为dgram。上面的例子使用的是TCP,因为SSH使用的是该协议。

黑名单规则的第三个字段指定协议。可以指定以下协议:tcpudptcp6udp6,或者通配符,如示例中的通配符,通常用于匹配所有的协议,除非有理由用某种协议来区分流量。

在第四个字段中,定义了报告事件的守护进程的有效用户或所有者。这里可以使用用户名或UID,也可以使用通配符(见上面的示例规则)。

数据包筛选器规则名称由第五个字段声明,该字段启动规则的行为部分。默认情况下,黑名单将所有块置于 pf 锚点下,名为 blacklistd,位于 pf.conf,如下所示:

anchor "blacklistd/*" in on $ext_if
block in
pass out

对于独立黑名单,可以在这个字段中使用一个锚名(anchor name)。在其他情况下,使用通配符就可以了。当一个名称以连字符开头(-)时,意味着应该使用一个带有默认规则名称的锚。在上面的例子中,一个使用连字符的修改后的例子是这样的:

ssh             stream  *       *               -ssh       3       24h

使用这样的规则,新的黑名单规则都会添加到 blacklistd-ssh 中。

为了阻止整个子网的单个规则违反,可以在规则名称中使用/。这将导致名称的剩余部分被解释为要应用到规则中指定的地址的掩码。例如,该规则将阻止每个与/24相邻的地址。

22              stream  tcp       *               */24    3       24h

注意:

重要的是要在这里指定正确的协议。IPv4 和 IPv6 对 /24 的处理方式是不同的,这也是为什么不能在第三个字段中使用 * 的原因。

这条规则规定,如果该网络中的任何一台主机行有异常行为,该网络上的其他所有主机也会被屏蔽。

第六个字段,称为nfail,它用于设置一个 IP 在登入失败多少次后加入黑名单。当在这个位置使用通配符时,意味着永远不会加入黑名单。在上面的示例规则中,定义了三个限制,这意味着在一个连接上三次尝试登录SSH失败后,该IP加入黑名单。

在 blacklistd 规则定义中的最后一个字段指定主机多久列入黑名单。默认单位是秒,使用后缀如m, h, 和 d 可指定时间单位米,小时和天。

该示例规则的全部含义是,在三次验证到SSH后,将导致该主机的PF块规则产生一个新的PF块规则。规则匹配是通过先对本地规则进行逐一检查,从最具体到最不具体的规则进行匹配。当发生匹配时,remote规则被应用,并命名、nfail和disable字段被匹配的remote规则更改。

30.6.2.2. 远程规则

远程规则用于指定 blacklistd 如何根据当前被评估的远程主机改变其行为。远程规则中的每个字段和本地规则中的字段是一样的。唯一的区别在于 blacklistd 使用这些规则的方式。为了解释它,来看这个示例规则:

[remote]
203.0.113.128/25 *      *       *               =/25    =       48h

地址字段可以是一个IP地址(v4或v6)、一个端口或两者都可以。这样就可以为特定的远程地址范围设置特殊的规则,就像这个例子一样。类型、协议和所有者字段的解释与本地规则中的相同。

但名称字段是不同的:远程规则中的等号(=)告诉blacklistd使用匹配的本地规则的值。这意味着防火墙规则条目被取下,并添加了/25前缀(netmask为255.255.255.128)。当来自该地址范围的连接被列入黑名单时,整个子网都会受到影响。这里也可以使用PF的锚名,在这种情况下,blacklistd将为这个地址块添加规则到这个名字的锚。当指定通配符时,将使用默认表。

可以在nfail栏中为一个地址定义一个自定义的失败次数。这对于特定规则的例外情况是很有用的,也许可以让某人在登录时对规则的应用不那么严格,或者在登录尝试时更宽松一些。当在这个第六个字段中使用星号时,阻止是被禁用的。

与办公室等本地网络的登录尝试相比,远程规则允许对登录尝试进行更严格的限制。

30.6.3. 黑名单客户端配置

FreeBSD 中有一些软件包可以利用黑名单的功能。两个最突出的是ftpd(8)sshd(8)来阻止过度的连接尝试。要激活 SSH 守护进程中的黑名单,请向/etc/ssh/sshd_config添加以下行:

UseBlacklist yes

之后重新启动 sshd,使这些更改生效。

ftpd(8)的黑名单是使用-B启用的,可以在/etc/inetd.conf中,或者在/etc/rc.conf中添加标志,比如这样:

ftpd_flags="-B"

这就是该程序配置黑名单的全部步骤。

30.6.4. 管理 Blacklistd

Blacklistd 为用户提供了一个名为blacklistctl(8)的管理工具。它根据 blacklistd.conf(5)中定义的规则,显示被阻止的地址和网络。要查看当前被阻止的主机列表,请使用dump-b结合使用,就像这样。

# blacklistctl dump -b
      address/ma:port id      nfail   last access
213.0.123.128/25:22   OK      6/3     2019/06/08 14:30:19

这个示例显示,端口22上来自地址范围 213.0.123.128/25 的尝试有6次,其中有三次是被允许的。列出的尝试次数比允许次数多,是由于SSH允许单个客户端从一个TCP连接上发起多次登录尝试。当前正在进行的连接不会被 blacklistd 停止。最后的连接尝试被列在 last access 输出列中。

要查看该主机将被列入黑名单的剩余时间,请添加 -r 到上一个命令中。

# blacklistctl dump -br
      address/ma:port id      nfail   remaining time
213.0.123.128/25:22   OK      6/3     36s

在这个例子中,该主机还有 36 秒解除屏蔽。

30.6.5. 从阻止列表中删除主机

有时需要在剩余时间结束前将主机从封堵列表中删除。不幸的是,blacklistd中没有这样的功能。不过,可以使用 pfctl 从 PF 表中删除该地址。对于被阻塞的端口,在/etc/pf.conf中定义的blacklistd锚里面都有一个子锚。例如, 如果有一个用于封堵 port 22 的子锚, 则称为 blacklistd/22。在这个子锚里面有一个表,包含了被封堵的地址。这个表叫做port,后面是端口号。在这个例子中,它被称为port22。有了这些信息,现在就可以使用 pfctl(8)来显示所有的地址, 就像这样:

# pfctl -a blacklistd/22 -t port22 -T show
...
213.0.123.128/25
...

在确定了要从列表中解除封禁的地址后,用下面的命令将其从列表中删除:

# pfctl -a blacklistd/22 -t port22 -T delete 213.0.123.128/25

该地址现在已从PF中删除,但仍将显示在blacklistctl列表中,因为它不知道PF中的任何变化。blacklistd数据库中的条目最终会过期,最终会从其输出中删除。如果主机再次匹配了blacklistd中的某个块规则,该条目将再次被添加。

本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读 文档,如不能解决再联系 <questions@FreeBSD.org>.

关于本文档的问题请发信联系 <doc@FreeBSD.org>.