作者选择了COVID-19 救济基金来接受捐赠,作为Write for DOnations计划的一部分。
介绍
防火墙可以说是抵御网络攻击的最重要的防线之一。从头开始配置防火墙的能力是一种授权技能,使管理员能够控制他们的网络。
Packet Filter (PF)是一个著名的防火墙应用程序,由安全驱动的OpenBSD项目在上游维护。它更准确地表示为包过滤工具,因此得名,并以其简单的语法、用户友好性和广泛的功能而闻名。默认情况下,PF 是有状态的防火墙,将有关连接的信息存储在状态表中,可出于分析目的访问该表。PF 是 FreeBSD 基础系统的一部分,并得到了强大的开发人员社区的支持。尽管 FreeBSD 和 OpenBSD 版本的 PF 在内核架构方面存在差异,但通常它们的语法是相似的。根据它们的复杂性,可以修改通用规则集,以相对较少的工作量来处理任一分布。
在本教程中,您将在带有 PF 的 FreeBSD 12.1 服务器上从头开始构建防火墙。您将设计可用作未来项目模板的基本规则集。您还将探索 PF 的一些高级功能,例如数据包卫生、暴力预防、监控和日志记录以及其他第三方工具。
先决条件
在开始本教程之前,您需要以下内容:
- 1G FreeBSD 12.1 服务器(ZFS或UFS)。您可以使用我们的如何开始使用 FreeBSD 教程来将您的服务器设置为您喜欢的配置。
- FreeBSD 默认没有启用防火墙——定制是 FreeBSD 精神的标志。因此,当您第一次启动服务器时,您需要在配置 PF 时进行临时保护。如果您使用的是 DigitalOcean,则可以在启动服务器后立即启用云防火墙。有关配置云防火墙的说明,请参阅 DigitalOcean 的防火墙快速入门。如果您使用其他云提供商,请在开始之前确定获得即时保护的最快途径。无论您选择哪种方法,您的临时防火墙都必须只允许入站 SSH 流量,并且可以允许所有类型的出站流量。
第 1 步 – 建立您的初步规则集
您将通过起草初步规则集开始本教程,该规则集提供基本保护和从 Internet 访问关键服务的权限。此时,您有一个正在运行的 FreeBSD 12.1 服务器,并带有一个活动的云防火墙。
构建防火墙有两种方法:默认拒绝和默认允许。默认拒绝方法会阻止所有流量,并且只允许规则中指定的流量。默认的 permit 方法正好相反:它通过所有流量,并且只阻止规则中指定的内容。您将使用默认拒绝方法。
PF 规则集写在一个名为 的配置文件中/etc/pf.conf
,这也是它的默认位置。只要在/etc/rc.conf
配置文件中指定了这个文件存储在其他地方是可以的。在本教程中,您将使用默认位置。
使用您的非 root 用户登录到您的服务器:
- ssh freebsd@your_server_ip
接下来创建您的/etc/pf.conf
文件:
- sudo vi /etc/pf.conf
注意:如果您想在教程中的任何时候查看完整的基本规则集,您可以参考步骤 4或步骤 8 中的示例。
PF根据三个核心行动过滤数据包:block
,pass
,和match
。当与其他选项结合时,它们形成规则。当数据包满足规则中指定的标准时,就会采取行动。正如你所期待,pass
并且block
规则将pass
与block
交通。甲match
规则执行当它找到一个匹配的标准上的分组的动作,但不通过或阻止它。例如,您可以对匹配的数据包执行网络地址转换(NAT),而不通过或阻止它,它会一直停留在那里,直到您告诉它在另一条规则中执行某些操作,例如将其路由到另一台机器或网关。
接下来将第一条规则添加到您的/etc/pf.conf
文件中:
block all
此规则会阻止各个方向的所有形式的流量。由于它没有指定方向,因此默认为in
和out
。此规则对于需要与外界隔离的本地工作站是合法的,但它在很大程度上是不切实际的,并且在远程服务器上不起作用,因为它不允许 SSH 流量。事实上,如果您启用了 PF,您就会将自己锁定在服务器之外。
/etc/pf.conf
使用以下突出显示的行修改您的文件以允许 SSH 流量:
block all
pass in proto tcp to port 22
注意:或者,您可以使用协议的名称:
block all
pass in proto tcp to port ssh
为了一致性,我们将使用端口号,除非有正当理由不这样做。文件中有协议及其各自端口号的详细列表,/etc/services
建议您查看。
PF 从上到下按顺序处理规则,因此您当前的规则集最初会阻止所有流量,但如果下一行的条件匹配,则通过它,在这种情况下是 SSH 流量。
您现在可以通过 SSH 连接到您的服务器,但您仍会阻止所有形式的出站流量。这是有问题的,因为您无法从 Internet 访问关键服务以安装软件包、更新时间设置等。
要解决此问题,请将以下突出显示的规则附加到/etc/pf.conf
文件末尾:
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }
您的规则集现在允许出站SSH、DNS、HTTP、NTP和 HTTPS 流量,并阻止所有入站流量(SSH 除外)。您将端口号和协议放在大括号内,这构成了 PF 语法中的列表,允许您根据需要添加更多端口号。您还为端口上的 UDP 协议添加了传递规则53
,123
因为 DNS 和 NTP 经常在 TCP 和 UDP 协议之间切换。您几乎完成了初步规则集,只需添加几条规则即可实现基本功能。
使用突出显示的规则完成初步规则集:
set skip on lo0
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass out inet proto icmp icmp-type { echoreq }
保存并退出文件。
您set skip
为环回设备创建规则,因为它不需要过滤流量并且可能会使您的服务器爬行。您pass out inet
为ICMP协议添加规则,该规则允许您使用ping(8)实用程序进行故障排除。该inet
选项代表IPv4地址族。
ICMP 是网络设备用于各种类型通信的多用途消息传递协议。例如,ping 实用程序使用一种称为echo request的消息,您已将其添加到icmp_type
列表中。作为预防措施,您只允许防止不受欢迎的设备联系您的服务器所需的消息类型。随着需求的增加,您可以向列表中添加更多的消息类型。
您现在拥有一个可为大多数机器提供基本功能的工作规则集。在下一节中,让我们通过启用 PF 并测试您的初步规则集来确认一切正常。
步骤 2 — 测试您的初步规则集
在此步骤中,您将测试您的初步规则集,并从您的云防火墙过渡到您的 PF 防火墙,让 PF 完全接管。您将使用该pfctl
实用程序激活您的规则集,该实用程序是 PF 的内置命令行工具,也是与 PF 交互的主要方法。
PF 规则集只不过是文本文件,这意味着加载新规则集不涉及任何复杂的过程。你可以加载一个新的规则集,旧的就不见了。很少(如果有的话)需要刷新现有的规则集。
FreeBSD 使用称为rc
系统的 shell 脚本网络来管理服务在启动时的启动方式;我们在各种rc
配置文件中指定这些服务。对于诸如 PF 之类的全局服务,您可以使用该/etc/rc.conf
文件。由于rc
文件对 FreeBSD 系统的健康至关重要,因此不应直接编辑它们。相反,FreeBSD 提供了一个命令行实用程序,sysrc
旨在帮助您安全地编辑这些文件。
让我们使用sysrc
命令行实用程序启用 PF :
- sudo sysrc pf_enable="YES"
- sudo sysrc pflog_enable="YES"
通过打印/etc/rc.conf
文件的内容来验证这些更改:
- sudo cat /etc/rc.conf
您将看到以下输出:
Outputpf_enable="YES"
pflog_enable="YES"
您还启用了该pflog
服务,这反过来又启用了pflogd
登录 PF的守护程序。(您将在后面的步骤中使用登录。
您在/etc/rc.conf
文件中指定了两个全局服务,但在您重新启动服务器或手动启动它们之前,它们不会初始化。重新启动服务器,以便您还可以测试您的 SSH 访问。
通过重新启动服务器来启动 PF:
- sudo reboot
连接将被断开。给它几分钟更新。
现在 SSH 回到服务器:
- ssh freebsd@your_server_ip
尽管您已经初始化了 PF 服务,但实际上还没有加载/etc/pf.conf
规则集,这意味着您的防火墙尚未激活。
加载规则集pfctl
:
- sudo pfctl -f /etc/pf.conf
如果没有错误或消息,则意味着您的规则集没有错误并且防火墙处于活动状态。
现在 PF 正在运行,您可以将服务器与云防火墙分离。这可以在您的 DigitalOcean 帐户的控制面板中通过从云防火墙的门户中删除您的 Droplet 来完成。如果您使用其他云提供商,请确保禁用您用于临时保护的任何内容。在服务器上运行两个不同的防火墙几乎肯定会导致问题。
为了更好的衡量,请再次重新启动您的服务器:
- sudo reboot
几分钟后,SSH 回到您的服务器:
- ssh freebsd@your_server_ip
PF 现在是您的代理防火墙。您可以通过使用 pfctl 实用程序访问一些数据来确保它正在运行。
让我们查看一些统计信息和计数器pfctl -si
:
- sudo pfctl -si
你传递-si
标志,代表show info。这是您可以与 pfctl 一起使用以解析有关防火墙活动的数据的众多过滤器参数组合之一。
您将看到以下表格数据(数值因机器而异):
OutputStatus: Enabled for 0 days 00:01:53 Debug: Urgent
State Table Total Rate
current entries 5
searches 144 1.3/s
inserts 11 0.1/s
removals 6 0.1/s
Counters
match 23 0.2/s
bad-offset 0 0.0/s
fragment 0 0.0/s
short 0 0.0/s
normalize 0 0.0/s
memory 0 0.0/s
bad-timestamp 0 0.0/s
congestion 0 0.0/s
ip-option 0 0.0/s
proto-cksum 0 0.0/s
state-insert 0 0.0/s
state-limit 0 0.0/s
src-limit 0 0.0/s
synproxy 0 0.0/s
map-failed 0 0.0/s
由于您刚刚激活了规则集,因此您还不会看到很多信息。然而,这个输出显示 PF 已经记录了 23 个匹配的规则,这意味着你的规则集的标准被匹配了 23 次。输出还确认您的防火墙正在工作。
您的规则集还允许出站流量从 Internet 访问一些关键服务,包括 ping 实用程序。
让我们用 ping 来检查互联网连接和 DNS 服务google.com
:
- ping -c 3 google.com
由于您运行了 count flag -c 3
,您将看到三个成功的连接响应:
OutputPING google.com (172.217.0.46): 56 data bytes
64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms
64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms
64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms
确保您可以使用以下命令访问 pkgs 存储库:
- sudo pkg upgrade
如果有任何要升级的软件包,请继续升级它们。
如果这两个服务都在工作,则意味着您的防火墙正在工作,您现在可以继续。尽管您的初步规则集提供了保护和功能,但它仍然是一个基本规则集,可以使用一些增强功能。在其余部分中,您将完成基本规则集,并使用 PF 的一些高级功能。
第 3 步 – 完成您的基本规则集
在此步骤中,您将构建初步规则集以完成您的基本规则集。您将重新组织一些规则并使用更高级的概念。
合并宏和表
在您的初步规则集中,您将所有参数硬编码到每个规则中,即构成列表的端口号。这在未来可能变得无法管理,具体取决于您网络的性质。出于组织目的,PF 包括宏、列表和表格。您已经直接在规则中包含了列表,但您也可以将它们与规则分开,并使用宏将它们分配给变量。
打开您的文件以将您的一些参数传输到宏中:
- sudo vi /etc/pf.conf
现在将以下内容添加到规则集的最顶部:
vtnet0 = "vtnet0"
icmp_types = "{ echoreq }"
. . .
使用新变量修改之前的 SSH 和 ICMP 规则:
. . .
pass in on $vtnet0 proto tcp to port { 22 }
. . .
pass inet proto icmp icmp-type $icmp_types
. . .
您之前的 SSH 和 ICMP 规则现在使用宏。变量名称由 PF 的美元符号语法表示。您将vtnet0
接口分配给具有相同名称的变量作为一种形式,这使您可以选择在将来根据需要重命名它。面向公众的接口的其他常见变量名称包括$pub_if
或$ext_if
。
接下来,您将实现一个表,它类似于宏,但旨在保存 IP 地址组。让我们为不可路由的 IP 地址创建一个表,它经常在拒绝服务攻击(DOS) 中发挥作用。您可以使用RFC6890 中指定的 IP 地址,它定义了特殊用途的 IP 地址注册表。您的服务器不应通过面向公众的接口向这些地址发送数据包或从这些地址接收数据包。
通过在icmp_types
宏下直接添加以下内容来创建此表:
. . .
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 \
172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24 \
192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 \
240.0.0.0/4 255.255.255.255/32 }
. . .
现在为规则<rfc6890>
下方的表格添加set skip on lo0
规则:
. . .
set skip on lo0
block in quick on egress from <rfc6890>
block return out quick on egress to <rfc6890>
. . .
在此介绍return
选项,它补充了您的block out
规则。这将丢弃数据包并向尝试建立这些连接的主机发送RST 消息,这对于分析主机活动非常有用。然后,您添加egress
关键字,它会自动查找任何给定接口上的默认路由。这通常是一种更简洁的查找默认路由的方法,尤其是对于复杂网络。该quick
关键字立即执行规则,而不考虑规则集的其余部分。例如,如果具有不合逻辑 IP 地址的数据包尝试连接到服务器,您希望立即断开连接,并且没有理由通过规则集的其余部分运行该数据包。
保护您的 SSH 端口
由于您的 SSH 端口对公众开放,因此很容易被利用。攻击者更明显的警告信号之一是大量的登录尝试。例如,如果同一 IP 地址在一秒钟内尝试登录您的服务器 10 次,您可以假设它不是人手完成的,而是尝试破解您的登录密码的计算机软件。这些类型的系统攻击通常被称为蛮力攻击,如果服务器的密码较弱,通常会成功。
警告:我们强烈建议在所有服务器上使用公钥身份验证。请参阅 DigitalOcean 关于基于密钥的身份验证的教程。
PF 具有处理蛮力和其他类似攻击的内置功能。使用 PF,您可以限制单个主机允许的同时连接尝试次数。如果主机超过这些限制,连接将被断开,并且它们将被服务器禁止。要实现这一点,您将使用 PF 的过载机制,该机制维护一个禁止 IP 地址表。
修改您之前的 SSH 规则以限制来自单个主机的同时连接数,如下所示:
. . .
pass in on $vtnet0 proto tcp to port { 22 } \
keep state (max-src-conn 15, max-src-conn-rate 3/1, \
overload <bruteforce> flush global)
. . .
添加keep state
允许您定义过载表的状态标准的选项。您传递max-src-conn
参数以指定每秒允许来自单个主机的同时连接数,并传递参数以指定每秒允许来自单个主机max-src-conn-rate
的新连接数。您为 指定15
连接max-src-conn
,并3
为指定连接max-src-conn-rate
。如果主机超过了这些限制,则该overload
机制会将源 IP 添加到<bruteforce>
表中,从而禁止它们进入服务器。最后,该flush global
选项会立即断开连接。
您已在 SSH 规则中定义了重载表,但尚未在规则集中声明该表。
<bruteforce>
在icmp_types
宏下面添加表格:
. . .
icmp_types = "{ echoreq }"
table <bruteforce> persist
. . .
该persist
关键字允许规则集中存在空表。没有它,PF 会抱怨表中没有 IP 地址。
这些措施确保您的 SSH 端口受到强大的安全机制的保护。PF 允许您配置快速解决方案以防止灾难性的利用形式。在接下来的部分中,您将采取措施在数据包到达您的服务器时对其进行清理。
清理您的流量
注意:以下部分描述了 TCP/IP 协议套件的基本原理。如果您计划构建 Web 应用程序或网络,那么掌握这些概念对您最有利。看看 DigitalOcean 的网络术语、接口和协议介绍教程。
由于 TCP/IP 协议套件的复杂性以及恶意行为者的持久性,数据包到达时经常带有差异和模糊性,例如 IP 片段重叠、虚假 IP 地址等。您必须在流量进入系统之前对其进行消毒。这个过程的技术术语是规范化。
当数据通过互联网传输时,它通常在其源头被分解成更小的片段以适应目标主机的传输参数,在那里它被重新组装成完整的数据包。不幸的是,入侵者可以通过超出本教程范围的多种方式来劫持此过程。但是,使用 PF,您可以使用一个规则来管理碎片。PF 包含一个scrub
用于规范化数据包的关键字。
在规则scrub
前面直接添加关键字block all
:
. . .
set skip on lo0
scrub in all fragment reassemble max-mss 1440
block all
. . .
此规则将清理应用于所有传入流量。您包括fragment reassemble
防止碎片进入系统的选项。相反,它们被缓存在内存中,直到它们重新组合成完整的数据包,这意味着您的过滤规则将只需要处理统一数据包。您还包括该max-mss 1440
选项,它表示重组 TCP 数据包的最大段大小,也称为有效负载。您指定 1440 字节的值,这在大小和性能之间取得平衡,为标头留出足够的空间。
分段的另一个重要方面是称为最大传输单元(MTU)的术语。TCP/IP 协议使设备能够协商数据包大小以建立连接。目标主机使用 ICMP 消息通知源 IP 其 MTU,这个过程称为MTU 路径发现。特定的 ICMP 消息类型是目标不可达。您将通过将unreach
消息类型添加到icmp_types
列表来启用 MTU 路径发现。
您将使用服务器的默认 MTU 1500 字节,这可以通过以下ifconfig
命令确定:
- ifconfig
您将看到以下输出,其中包括您当前的 MTU:
Outputvtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
. . .
更新icmp_types
列表以包含目标不可达消息类型:
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach}"
. . .
现在您已经制定了处理碎片的策略,进入您系统的数据包将是统一和一致的。这是可取的,因为有很多设备通过互联网交换数据。
您现在将努力防止另一个称为IP 欺骗的安全问题。攻击者经常更改其源 IP,使其看起来好像位于组织内的受信任节点上。PF包括反欺骗用于处理伪造来源IP指令。当应用于特定接口时,反欺骗会阻止来自该接口网络的所有流量(除非它来自该接口)。例如,如果您对驻留在 的接口应用反欺骗,则5.5.5.1/24
来自5.5.5.0/24
网络的所有流量都无法与系统通信,除非它源自该接口。
添加以下突出显示的内容以将反欺骗应用到您的vtnet0
界面:
. . .
set skip on lo0
scrub in
antispoof quick for $vtnet0
block all
. . .
保存并退出文件。
此反欺骗规则表示来自vtnet0
网络的所有流量只能通过该vtnet0
接口,否则将使用quick
关键字立即丢弃。坏演员将无法隐藏在vtnet0
的网络中并与其他节点通信。
为了演示您的反欺骗规则,您将以详细的形式将规则集打印到屏幕上。PF 中的规则通常以缩写形式编写,但也可以以冗长形式编写。以这种方式编写规则通常是不切实际的,但出于测试目的,它可能很有用。
/etc/pf.conf
使用pfctl
以下命令打印using的内容:
- sudo pfctl -nvf /etc/pf.conf
此pfctl
命令采用-nvf
标志,这些标志打印规则集并在不实际加载任何内容的情况下对其进行测试,也称为试运行。您现在将看到/etc/pf.conf
详细形式的全部内容。
您将在反欺骗部分看到类似于以下输出的内容:
Output. . .
block drop in quick on ! vtnet0 inet from your_server_ip/20 to any
block drop in quick on ! vtnet0 inet from network_address/16 to any
block drop in quick inet from your_server_ip to any
block drop in quick inet from network_address to any
block drop in quick on vtnet0 inet6 from your_IPv6_address to any
. . .
您的反欺骗规则发现它是your_server_ip/20
网络的一部分。它还检测到(对于本教程的示例)服务器是network_address/16
网络的一部分,并且有一个额外的 IPv6 地址。反欺骗阻止所有这些网络与系统通信,除非它们的流量通过vtnet0
接口。
您的反欺骗规则是基本规则集的最后一项。在下一步中,您将启动这些更改并执行一些测试。
第 4 步 — 测试您的基本规则集
在此步骤中,您将检查并测试您的基本规则集,以确保一切正常运行。最好避免在没有测试的情况下一次实施太多规则。最佳实践是从基本要素开始,逐步扩展,然后在进行配置更改的同时进行备份。
这是您完整的基本规则集:
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 \
172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24 \
192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 \
240.0.0.0/4 255.255.255.255/32 }
set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
keep state (max-src-conn 15, max-src-conn-rate 3/1, \
overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types
/etc/pf.conf
在继续之前,请确保您的文件与此处的完整基本规则集相同。然后保存并退出文件。
您完整的基本规则集为您提供:
- 可以定义关键服务和设备的宏集合。
- 用于解决数据包碎片和不合逻辑的 IP 地址的网络卫生策略。
- 一个默认拒绝过滤,阻止一切,只允许您指定的内容结构。
- 入站 SSH 访问限制了主机可以进行的同时连接数。
- 出站流量策略可让您从 Internet 访问某些关键服务。
- 提供对 ping 实用程序和 MTU 路径发现的访问的 ICMP 策略。
运行以下pfctl
命令进行试运行:
- sudo pfctl -nf /etc/pf.conf
你传递了-nf
告诉pfctl
运行规则集而不加载它的标志,如果有任何错误,它会抛出错误。
现在,没有遇到错误,加载规则集:
- sudo pfctl -f /etc/pf.conf
如果没有错误,则意味着您的基本规则集处于活动状态并且运行正常。在本教程的前面,您将对规则集执行一些测试。
第一次测试互联网连接和 DNS 服务:
- ping -c 3 google.com
您将看到以下输出:
OutputPING google.com (172.217.0.46): 56 data bytes
64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms
64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms
64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms
然后,检查您是否到达了pkgs
存储库:
- sudo pkg upgrade
再次,如果需要升级软件包。
最后,重启你的服务器:
- sudo reboot
给您的服务器几分钟时间重新启动。您已经完成并实施了您的基本规则集,这是您进步的重要一步。您现在已准备好探索 PF 的一些高级功能。在下一步中,您将继续防止蛮力攻击。
第 5 步 – 管理您的重载表
随着时间的推移,<bruteforce>
过载表将充满恶意 IP 地址,需要定期清除。攻击者不太可能继续使用相同的 IP 地址,因此将它们长时间存储在过载表中是违反直觉的。
您将使用pfctl
以下命令手动清除已在过载表中存储 48 小时或更长时间的 IP 地址:
- sudo pfctl -t bruteforce -T expire 172800
您将看到类似于以下内容的输出:
Output0/0 addresses expired.
您传递-t bruteforce
代表table bruteforce的-T
标志和允许您运行一些内置命令的标志。在这种情况下,您运行expire
命令以清除所有条目,-t bruteforce
时间值以秒为单位。由于您在新服务器上工作,因此过载表中可能还没有 IP 地址。
此规则适用于快速修复,但更强大的解决方案是使用cron(FreeBSD 的作业调度程序)自动执行该过程。让我们创建一个 shell 脚本来运行这个命令序列。
在/usr/local/bin
目录下创建一个shell脚本文件:
- sudo vi /usr/local/bin/clear_overload.sh
在shell脚本中添加以下内容:
#!/bin/sh
pfctl -t bruteforce -T expire 172800
使用以下命令使文件可执行:
- sudo chmod 755 /usr/local/bin/clear_overload.sh
接下来,您将创建一个cron 作业。这些作业将根据您指定的时间重复运行。它们通常用于备份,或需要每天在同一时间运行的任何进程。您可以使用crontab文件创建 cron 作业。请参阅手册页以了解有关cron(8)和crontab(5) 的更多信息。
使用以下命令创建 root 用户 crontab 文件:
- sudo crontab -e
现在将以下内容添加到 crontab 文件中:
# minute hour mday month wday command
* 0 * * * /usr/local/bin/clear_overload.sh
保存并退出文件。
注意:如果添加内容时未正确对齐,请将每个值与其对应的表条目对齐以提高可读性。
这个cron 作业clear_overload.sh
每天在午夜运行脚本,从过载表中 删除 48 小时前的 IP 地址<bruteforce>
。接下来,您将向规则集添加锚点。
第 6 步 — 将锚点引入您的规则集
在此步骤中,您将引入anchors,它们用于将规则来源手动或从外部文本文件导入主规则集。锚点可以包含规则片段、表格,甚至其他锚点,称为嵌套锚点。让我们通过将表添加到外部文件并将其导入到您的基本规则集来演示锚点的工作原理。您的表将包含一组您希望阻止它们连接到外部世界的内部主机。
创建一个名为 的文件/etc/blocked-hosts-anchor
:
- sudo vi /etc/blocked-hosts-anchor
将以下内容添加到文件中:
table <blocked-hosts> { 192.168.47.1 192.168.47.2 192.168.47.3 }
block return out quick on egress from <blocked-hosts>
保存并退出文件。
这些规则声明并定义了<blocked-hosts>
表,然后阻止表中的每个IP地址<blocked-hosts>
访问外界的服务。您可以使用egress
关键字作为查找 Internet 的默认路由或出路的首选方法。
您仍然需要在/etc/pf.conf
文件中声明锚点:
- sudo vi /etc/pf.conf
现在在规则之后添加以下锚规则block all
:
. . .
block all
anchor blocked_hosts
load anchor blocked_hosts from "/etc/blocked-hosts-anchor"
. . .
保存并退出文件。
这些规则声明blocked_hosts
锚规则并将锚规则从/etc/blocked-hosts-anchor
文件加载到主规则集。
现在通过使用以下命令重新加载规则集来启动这些更改pfctl
:
- sudo pfctl -f /etc/pf.conf
如果没有错误,则意味着您的规则集中没有错误并且您的更改处于活动状态。
使用pfctl
来验证你的锚正在运行:
- sudo pfctl -s Anchors
该-s Anchors
标志代表“节目主播”。您将看到以下输出:
Outputblocked_hosts
该pfctl
实用程序还可以使用-a
和-s
标志解析锚点的特定规则:
- sudo pfctl -a blocked_hosts -s rules
您将看到以下输出:
Outputblock return out quick on egress from <blocked-hosts> to any
锚点的另一个特点是它们允许您按需添加规则,而无需重新加载规则集。这对于测试、快速修复、紧急情况等非常有用。例如,如果内部主机的行为很奇怪,并且您想阻止它进行向外连接,则可以在适当的位置设置一个锚点,以便您可以从命令行快速进行干预。
让我们打开/etc/pf.conf
并添加另一个锚点:
- sudo vi /etc/pf.conf
您将命名锚点rogue_hosts
,并将其放置在block all
规则中:
. . .
block all
anchor rogue_hosts
. . .
保存并退出文件。
要启动这些更改,请使用以下命令重新加载规则集pfctl
:
- sudo pfctl -f /etc/pf.conf
再次使用pfctl
来验证锚点是否正在运行:
- sudo pfctl -s Anchors
这将生成以下输出:
Outputblocked_hosts
rogue_hosts
现在锚点正在运行,您可以随时向其添加规则。通过添加以下规则来测试:
- sudo sh -c 'echo "block return out quick on egress from 192.168.47.4" | pfctl -a rogue_hosts -f -'
这将调用echo
命令及其字符串内容,然后将其pfctl
通过管道传送到带有|
符号的实用程序中,在那里将其处理为锚规则。您使用该sh -c
命令打开另一个 shell 会话。这是因为您在两个进程之间建立了一个管道,但需要sudo
在整个命令序列中持续存在的特权。有多种方法可以解决这个问题;在这里,您可以使用 .sudo 权限打开一个额外的 shell 进程sudo sh -c
。
现在,pfctl
再次使用来验证这些规则是否有效:
- sudo pfctl -a rogue_hosts -s rules
这将生成以下输出:
Outputblock return out quick on egress inet from 192.168.47.4 to any
锚点的使用完全取决于情境,而且通常是主观的。与任何其他功能一样,使用锚点也有利有弊。一些应用程序,例如设计带有锚点的blacklistd界面。接下来,您将专注于使用 PF 进行日志记录,这是网络安全的一个关键方面。如果您看不到防火墙在做什么,您的防火墙就没有用处。
第 7 步 — 记录防火墙的活动
在此步骤中,您将使用 PF 日志记录,它由名为pflog
. 日志记录在启动时通过添加pflog_enabled=YES
到/etc/rc.conf
文件中启用,您在第 2 步中完成了此操作。这将启用pflogd守护程序,该守护程序调出一个名为的接口并将pflog0
二进制格式的日志写入名为/var/log/pflog
. 日志可以从接口实时解析,或/var/log/pflog
使用tcpdump(8)实用程序从文件中读取。
首先从/var/log/pflog
文件中访问一些日志:
- sudo tcpdump -ner /var/log/pflog
您传递-ner
格式化输出以提高可读性的标志,并指定一个要读取的文件,在您的情况下是/var/log/pflog
.
您将看到以下输出:
Outputreading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)
在这些早期阶段,文件中可能没有任何数据/var/log/pflog
。在短时间内,日志文件将开始增长。
您还可以pflog0
使用以下命令从界面实时查看日志:
- sudo tcpdump -nei pflog0
您传递-nei
标志,这些标志也格式化输出以提高可读性,但这次指定一个接口,在您的情况下是pflog0
.
您将看到以下输出:
Outputtcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 262144 bytes
您现在将实时看到连接。如果可能,从远程机器 ping 您的服务器,您将看到连接发生。服务器将保持此状态,直到您退出。
要退出此状态并返回到命令行,请点击CTRL + Z
。
互联网上有大量关于tcpdump(8) 的信息,包括官方网站。
使用 pftop 访问日志文件
该pftop
实用程序是一种用于实时快速查看防火墙活动的工具。它的名字受著名的 Unixtop
实用程序的影响。
要使用它,您需要安装pftop
软件包:
- sudo pkg install pftop
现在运行pftop
二进制文件:
- sudo pftop
这将生成以下输出(您的 IP 会有所不同):
OutputPR DIR SRC DEST STATE AGE EXP PKTS BYTES
tcp In 251.155.237.90:27537 157.225.173.58:22 ESTABLISHED:ESTABLISHED 00:12:35 23:59:55 1890 265K
tcp In 222.186.42.15:25884 157.225.173.58:22 TIME_WAIT:TIME_WAIT 00:01:25 00:00:06 22 3801
udp Out 157.245.171.59:4699 67.203.62.5:53 MULTIPLE:SINGLE 00:00:14 00:00:16 2 227
创建额外的日志接口
与任何其他界面一样,可以使用/etc/hostname
文件创建和命名多个日志界面。您可能会发现这对组织目的很有用,例如,如果您想单独记录某些类型的活动。
创建一个名为 的附加日志记录接口pflog1
:
- sudo vi /etc/hostname.pflog1
将以下内容添加到/etc/hostname.pflog1
文件中:
up
现在在您的/etc/rc.conf
文件中在启动时启用设备:
- sudo sysrc pflog1_enable="YES"
您现在可以监控和记录您的防火墙活动。这使您可以查看谁在与您的服务器建立连接以及正在建立的连接类型。
在本教程中,您已将一些高级概念纳入您的 PF 规则集。只需在需要时实现高级功能。也就是说,在下一步中,您将恢复到基本规则集。
步骤 8 — 恢复到您的基本规则集
在这最后一部分中,您将恢复到您的基本规则集。这是一个快速的步骤,它将带您回到功能的极简状态。
使用以下命令打开基本规则集:
- sudo vi /etc/pf.conf
删除文件中的当前规则集并将其替换为以下基本规则集:
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 \
172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24 \
192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 \
240.0.0.0/4 255.255.255.255/32 }
set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
keep state (max-src-conn 15, max-src-conn-rate 3/1, \
overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types
保存并退出文件。
重新加载规则集:
- sudo pfctl -f /etc/pf.conf
如果命令没有错误,那么您的规则集中没有错误并且您的防火墙运行正常。
您还需要禁用pflog1
您创建的接口。由于您可能还不知道您是否需要它,您可以pflog1
使用该sysrc
实用程序禁用它:
- sudo sysrc pflog1_enable="NO"
现在/etc/hostname.pflog1
从/etc
目录中删除文件:
- sudo rm /etc/hostname.pflog1
在注销之前,再次重新启动服务器以确保您的所有更改都有效且持久:
- sudo reboot
在登录到您的服务器之前等待几分钟。
或者,如果您想使用网络服务器实现 PF,以下是此场景的规则集。对于大多数 Web 应用程序来说,这个规则集是一个足够的起点。
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <webcrawlers> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 \
172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24 \
192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 \
240.0.0.0/4 255.255.255.255/32 }
set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
keep state (max-src-conn 15, max-src-conn-rate 3/1, \
overload <bruteforce> flush global)
pass in on $vtnet0 proto tcp to port { 80 443 } \
keep state (max-src-conn 45, max-src-conn-rate 9/1, \
overload <webcrawlers> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types
这将创建一个名为超载表<webcrawlers>
,具有比基于的价值你的SSH端口更自由的过载的政策max-src-conn 45
和max-src-conn-rate
。这是因为并非所有的重载都来自坏演员。它们也可能来自非恶意的网络机器人,因此您可以避免对端口80
和443
. 如果您决定实施网络服务器规则集,则需要将<webcrawlers>
表添加到/etc/pf.conf
,并定期从表中清除 IP。为此,请参阅步骤 5。
结论
在本教程中,您在 FreeBSD 12.1 上配置了 PF。您现在有一个基本规则集,可以作为您所有 FreeBSD 项目的起点。有关 PF 的更多信息,请查看pf.conf(5)手册页。
访问我们的FreeBSD 主题页面以获取更多教程和问答。