ubuntu20使用iptables-persistent libfakeroot libxtables-dev netfilter-persistent
实施防火墙是保护服务器安全的重要一步。其中很大一部分是决定将对您的网络实施流量限制的单个规则和策略。像iptables
这样的防火墙还允许您对应用规则的结构框架有发言权。
在本指南中,您将学习如何构建防火墙,作为更复杂规则集的基础。该防火墙将主要关注提供合理的默认值和建立鼓励扩展性的框架。
先决条件
要完成本教程,您需要使用配置了sudo
权限的非根用户访问Ubuntu 20.04服务器。除了步骤4,您可以按照我们的Ubuntu 20.04初始服务器安装指南中概述的所有步骤进行操作,因为我们将在本教程中设置防火墙。
此外,我们建议检查您希望实施的防火墙策略。您可以按照本指南更好地了解需要考虑的内容。
安装持久防火墙服务
首先更新本地包缓存:
sudo apt update
现在安装iptables-persistent
软件包。这允许您保存规则集,并在引导时自动应用它们:
sudo apt install iptables-persistent
在安装过程中,系统会询问您是否要保存当前规则,请选择**<Yes>**。请注意,您将运行netfilter-persistent
命令来执行iptables
永久防火墙服务。接下来,您将编辑生成的规则文件。
本指南中关于IPv6的说明
在开始之前,我们将简要讨论IPv4与IPv6。iptables
命令仅处理IPv4流量。对于IPv6流量,使用了一个名为ip6tables
的单独配套工具。规则存储在单独的表和链中。对于netfilter-persistent
命令,IPv4规则写入/etc/iptables/rules.v4
并从中读取,IPv6规则存储在/etc/iptables/rules.v6
中。
本指南假设您没有在服务器上积极使用IPv6。如本指南所示,如果您的服务不利用IPv6,则完全阻止访问更安全。
实施基本防火墙策略(快捷方式)
为了尽快启动和运行,我们将向您展示如何直接编辑规则文件,并复制和粘贴完成的防火墙策略。之后,我们将解释一般策略,以及如何使用iptables
命令而不是修改文件来实现这些规则。
为了实现防火墙策略和框架,您将编辑/etc/iptables/rules.v4
和/etc/iptables/rules.v6
文件。在首选的文本编辑器中打开rules.v4
文件。在这里,我们将使用nano
:
sudo nano /etc/iptables/rules.v4
在内部,该文件将包含以下内容:
/etc/iptables/rules.v4
# Generated by iptables-save v1.8.4 on Tue Mar 1 19:03:10 2022
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Tue Mar 1 19:03:10 2022
删除这些内容并替换为以下内容:
/etc/iptables/rules.v4
*filter
# Allow all outgoing, but drop incoming and forwarding packets by default
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# Custom per-protocol chains
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]
# Acceptable UDP traffic
# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
# Acceptable ICMP traffic
# Boilerplate acceptance policy
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
# Drop invalid packets
-A INPUT -m conntrack --ctstate INVALID -j DROP
# Pass traffic to protocol-specific chains
## Only allow new connections (established and related should already be handled)
## For TCP, additionally only allow new SYN packets since that is the only valid
## method for establishing a new TCP connection
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
# Reject anything that's fallen through to this point
## Try to be protocol-specific w/ rejection message
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
# Commit the changes
COMMIT
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
保存并关闭文件。如果使用nano
,可以按CTRL + X
,然后按Y
和ENTER
。
您可以通过运行以下命令来测试文件的语法错误。如果收到以下任何错误,请确保修复语法错误:
sudo iptables-restore -t /etc/iptables/rules.v4
接下来,打开/etc/iptables/rules.v6
文件以修改IPv6规则:
sudo nano /etc/iptables/rules.v6
该文件将包含以下内容:
/etc/iptables/rules.v6
# Generated by ip6tables-save v1.8.4 on Tue Mar 1 19:03:10 2022
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Tue Mar 1 19:03:10 2022
您可以通过使用以下配置替换文件内容来阻止所有IPv6通信:
/etc/iptables/rules.v6
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
*raw
:PREROUTING DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
*nat
:PREROUTING DROP [0:0]
:INPUT DROP [0:0]
:OUTPUT DROP [0:0]
:POSTROUTING DROP [0:0]
COMMIT
*security
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
*mangle
:PREROUTING DROP [0:0]
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
:POSTROUTING DROP [0:0]
COMMIT
保存并关闭文件。
要测试此文件的语法错误,请使用ip6tables-restore
命令和-t
选项:
sudo ip6tables-restore -t /etc/iptables/rules.v6
当两个规则文件都没有报告语法错误时,您可以通过运行以下命令来应用设置的规则:
sudo service netfilter-persistent reload
Output * Loading netfilter rules...
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start
[ OK ]
这将立即实施文件中列出的策略。您可以通过列出当前使用的iptables
条规则来验证这一点。首次检查IPv4:
sudo iptables -S
Output-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-N ICMP
-N TCP
-N UDP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
-A TCP -p tcp -m tcp --dport 22 -j ACCEPT
然后检查当前的IPv6规则:
sudo ip6tables -S
Output-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
这些防火墙规则将在每次启动时重新应用。测试它以确保您仍然可以登录,并且所有其他访问都被阻止。
解释我们的通用防火墙策略
在使用上一节中的规则构建的基本防火墙中,我们创建了一个可扩展的框架,可以对其进行调整以添加或删除规则。对于IPv4流量,我们主要关注filter
表中的INPUT
链。该链将处理所有发送到服务器的数据包。我们还允许所有传出流量并拒绝所有数据包转发,这仅适用于此服务器充当其他主机的路由器的情况。我们接受所有其他表中的数据包,因为我们只想在本指南中过滤数据包。
一般来说,我们的规则设置了防火墙,默认情况下会拒绝传入流量。然后,我们为希望从该策略中排除的服务和流量类型创建例外。
在主要的INPUT
链中,我们为流量添加了一些通用规则,我们相信这些规则将始终以相同的方式处理。例如,我们总是想拒绝被视为“无效”的数据包,并且我们总是想允许本地环回接口上的流量和与已建立连接相关的数据。
然后,我们根据流量使用的协议匹配流量,并将其洗牌到特定于协议的链。这些特定于协议的链旨在保存匹配的规则,并允许特定服务的流量。在本例中,我们允许的唯一服务是TCP
链中的SSH。如果我们提供另一种服务,比如HTTP(S)服务器,我们也可以在这里添加异常。这些链条将是您大多数定制的焦点。
任何与协议特定链中的通用规则或服务规则不匹配的流量都由INPUT
链中的最后几条规则处理。我们已将防火墙的默认策略设置为DROP
,这将拒绝通过我们的规则的数据包。然而,INPUT
链末端的规则拒绝数据包,并向客户端发送一条消息,模拟服务器在该端口上没有运行服务时的响应方式。
对于IPv6流量,我们放弃了所有流量。我们的服务器未使用此协议,因此最安全的做法是根本不参与流量。
使用iptables
命令实现防火墙
现在,您已经了解了我们构建的策略背后的总体思想,我们将讨论如何使用iptables
个命令创建这些规则。我们最终将使用上面指定的相同规则,但我们将通过迭代添加规则来创建策略。因为iptables
立即应用每个规则,所以规则排序非常重要(例如,我们将拒绝数据包的规则保留到最后)。
重置防火墙
首先重置防火墙规则,以便查看如何从命令行构建策略。运行以下命令刷新所有规则:
sudo service netfilter-persistent flush
现在验证规则是否已重置:
sudo iptables -S
您应该有输出,显示filter
表中的规则已消失,并且所有链上的默认策略设置为ACCEPT
:
Output-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
创建协议特定链
接下来,您将创建所有特定于协议的链。这些将用于保存为要公开的服务创建拒绝策略例外的规则。您将为UDP
流量创建一个:
sudo iptables -N UDP
然后是TCP
的另一个:
sudo iptables -N TCP
ICMP
还有一个:
sudo iptables -N ICMP
接下来,为SSH流量添加异常。SSH使用TCP,因此您将添加一个规则,以接受发送到端口22
的TCP
流量到TCP链:
sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT
如果您想添加额外的TCP服务,现在可以通过替换端口号重复该命令来完成。
创建通用接受和拒绝规则
在INPUT
链中,所有传入流量开始过滤,我们需要添加通用规则。这些是一些常识规则,通过接受低风险的流量(本地流量和与我们已经检查的连接相关的流量)和丢弃明显无用的流量(无效数据包),为防火墙设置基线。
首先,创建一个例外,以接受作为已建立连接的一部分或与已建立连接相关的所有流量:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
该规则使用conntrack
扩展,该扩展提供了内部跟踪,因此iptables
具有所需的上下文,以将数据包作为更大连接的一部分进行评估,而不是作为离散的、不相关的数据包流。TCP是一种基于连接的协议,因此已建立的连接定义得相当好。对于UDP和其他无连接协议,已建立的连接指的是已看到响应的流量(原始数据包的源将是响应数据包的目的地,反之亦然)。相关连接是指与现有连接关联启动的新连接。这里的经典示例是FTP数据传输连接,它与已经建立的FTP控制连接有关。
您还需要允许来自本地环回接口的所有流量。这是由服务器生成并发送到服务器的流量。主机上的服务使用它来相互通信:
sudo iptables -A INPUT -i lo -j ACCEPT
最后,拒绝所有无效数据包。由于多种原因,数据包可能无效。它们可能指的是不存在的连接,可能指向不存在的接口、地址或端口,也可能格式不正确。在任何情况下,您都会丢弃所有无效数据包,因为没有适当的方法来处理它们,而且它们可能代表恶意活动:
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
创建到协议特定链的跳转规则
到目前为止,我们已经在INPUT
链中创建了一些一般规则,并在我们的协议特定链中为特定的可接受服务创建了一些规则。然而,目前,流量进入INPUT
链,无法到达我们的协议特定链。
现在,您需要将INPUT
链中的流量引导到适当的协议特定链中。您可以匹配协议类型以将其发送到正确的链。此外,确保数据包代表一个新的连接(任何已建立的或相关的连接都应该提前处理)。从UDP
流量开始:
sudo iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
接下来,对TCP
流量运行以下命令。请注意,对于TCP数据包,您将添加额外的要求,即数据包是_SYN_数据包,这是启动TCP连接的唯一有效类型:
sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
然后对ICMP
流量运行以下操作:
sudo iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
拒绝所有剩余流量
如果传递给协议特定链的数据包不符合其中的任何规则,则控制将传递回INPUT
链。防火墙不允许任何达到这一点的行为。
您将使用REJECT
目标拒绝流量,该目标向客户端发送响应消息。这允许您指定出站消息传递,以便您可以模拟客户端尝试将数据包发送到常规封闭端口时将给出的响应。响应取决于客户端使用的协议。
试图到达关闭的UDP
端口将导致ICMP
消息,说明“无法访问端口”。您可以通过运行以下命令来模拟此操作:
sudo iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
尝试在封闭端口上建立TCP
连接会导致TCP RST响应:
sudo iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
对于所有其他数据包,您可以发送ICMP
“protocol unreachable”消息,以指示服务器不响应该类型的数据包:
sudo iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
调整默认策略
您添加的最后三条规则应处理INPUT
链中的所有剩余流量。但是,作为预防措施,您应该将默认策略设置为DROP
,如下所示:
sudo iptables -P INPUT DROP
如果此服务器未配置为其他机器的路由器,则还应在FORWARD
链中设置此策略:
sudo iptables -P FORWARD DROP
**警告:**当策略设置为DROP
时,如果用sudo iptables -F
清除iptables
,则当前SSH连接将被删除!使用sudo netfilter-persistent flush
刷新是清除规则的更好方法,因为它还将重置默认策略。
为了匹配删除所有流量的IPv6策略,可以使用以下ip6tables
命令,从INPUT
开始:
sudo ip6tables -P INPUT DROP
然后对FORWARD
运行以下操作:
sudo ip6tables -P FORWARD DROP
最后,设置OUTPUT
的策略:
sudo ip6tables -P OUTPUT DROP
这应该相当紧密地复制您的规则集。
保存iptables
条规则
在这一点上,你应该测试你的防火墙规则,确保它们阻止了你想要阻止的流量,同时不妨碍你的正常访问。一旦您确信您的规则运行正常,您可以保存它们,以便它们在引导时自动应用于您的系统。
通过运行以下命令保存当前规则(IPv4和IPv6):
sudo service netfilter-persistent save
这将使用您在命令行上制定的策略覆盖/etc/iptables/rules.v4
和/etc/iptables/rules.v6
文件。
结论
通过遵循本指南,或者直接将防火墙规则粘贴到配置文件中,或者在命令行上手动应用并保存它们,您已经创建了一个良好的初始防火墙配置。您必须添加单独的规则,以允许访问您想要提供的服务。
本指南中建立的框架应允许您进行调整,并有助于澄清您现有的政策。查看我们的其他一些指南,了解如何使用一些流行的服务构建防火墙策略:
-
Iptables要点:通用防火墙规则和命令
-
如何设置Iptables防火墙以保护服务器之间的通信
-
如何通过带有Iptables的Linux网关转发端口
-
如何使用Nmap和Tcpdump测试防火墙配置