https://wiki.archlinux.org/index.php/Simple_stateful_firewall#Port_knocking
先决条件
首先,安装userland实用程序iptables或验证它们是否已经安装。
本文假设当前没有设置iptables规则。要检查当前规则集并验证当前没有运行以下规则的规则:
#iptables-save
#生成的iptables-save v1.4.19.1在Thu Aug 1 19:28:53 2013
*过滤
:INPUT ACCEPT [50:3763]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [30:3472]
承诺
#完成于8月1日19:28:53 2013
要么
#iptables -nvL --line-numbers
链输入(策略ACCEPT 156数据包,12541字节)
num pkts字节目标prot opt输出源目的地
链前进(策略ACCEPT 0数据包,0字节)
num pkts字节目标prot opt输出源目的地
链输出(策略ACCEPT 82数据包,8672字节)
num pkts字节目标prot opt输出源目的地
如果有规则,您可以通过加载默认规则集来重置规则:
#iptables-restore </etc/iptables/empty.rules
否则,请参阅Iptables#重置规则。
单机的防火墙
创建必要的链
对于这个基本设置,我们将创建两个用户定义的链,我们将使用它们来打开防火墙中的端口。
#iptables -N TCP
#iptables -N UDP
链当然可以具有任意名称。我们选择这些只是为了匹配我们想要处理的协议,在后面的规则中,它们是用协议选项指定的,例如-p tcp
always。
FORWARD链
如果您要将设备设置为NAT网关,请查看#设置NAT网关。然而,对于单个机器,我们简单地将FORWARD链的策略设置为DROP并继续:
#iptables -P FORWARD DROP
OUTPUT链
我们不打算过滤任何传出的流量,因为这将使设置更复杂,需要一些额外的思考。在这种简单的情况下,我们将OUTPUT策略设置为ACCEPT。
#iptables -P OUTPUT ACCEPT
INPUT链
类似于以前的链,我们将INPUT链的默认策略设置为DROP,以防万一某些原因违反我们的规则。删除所有流量并指定允许的是创建安全防火墙的最佳方法。
#iptables -P INPUT DROP
任何网络接口接收到的每个数据包都将首先通过INPUT链,如果它是发往本机的。在这个链中,我们确保只接受我们想要的数据包。
添加到INPUT链的第一个规则将允许属于已建立连接的流量,或与这些连接相关的新有效流量,例如ICMP错误或回应应答(主机在ping时返回的数据包)。ICMP代表Internet控制消息协议。一些ICMP消息是非常重要的,并且帮助管理拥塞和MTU,并且被这条规则接受。
连接状态ESTABLISHED
意味着在设置规则时,其他规则先前允许initial(--ctstate NEW
)连接尝试或连接已处于活动状态(例如活动的远程SSH连接)
#iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
第二个规则将接受来自“环回”(lo)接口的所有流量,这对于许多应用和服务是必要的。
#iptables -A INPUT -i lo -j ACCEPT
第三个规则将删除所有具有“INVALID”状态匹配的流量。流量可以分为四个“状态”类别:新建,已建立,相关或无效,这是什么使得这是一个“有状态”防火墙,而不是不安全的“无状态”。使用“nf_conntrack_ *”内核模块跟踪状态,在添加规则时由内核自动加载。
#iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
下一个规则将接受所有新的传入ICMP回显请求,也称为ping。只有第一个数据包计数为NEW,其余数据包将由RELATED,ESTABLISHED规则处理。由于计算机不是路由器,不需要允许具有状态NEW的其他ICMP流量。
#iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
现在我们将TCP和UDP链连接到INPUT链以处理所有新的传入连接。一旦连接被TCP或UDP链接受,它由RELATED / ESTABLISHED流量规则处理。TCP和UDP链将接受新的传入连接,或礼貌地拒绝它们。必须使用SYN数据包启动新的TCP连接。
#iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
#iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
如果端口未打开,我们拒绝TCP连接与TCP RESET数据包和UDP数据流与ICMP端口不可达消息。这模仿默认的Linux行为(符合RFC),并允许发送方快速关闭连接和清理。
#iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
#iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
对于其他协议,我们向INPUT链添加最终规则,以使用icmp协议不可达消息拒绝所有剩余的传入流量。这模仿了Linux的默认行为。
#iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
示例iptables.rules文件
iptables.rules
运行上面所有命令后的文件示例:
/etc/iptables/iptables.rules
#生成的iptables-save v1.4.18在Sun Mar 17 14:21:12 2013
*过滤
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:TCP - [0:0]
:UDP - [0:0]
-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 icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-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
承诺
#完成于2013年3月17日14:21:12 2013
此文件可以使用以下命令生成:
#iptables-save> /etc/iptables/iptables.rules
并可用于继续以下部分。如果您通过SSH远程设置防火墙,请在继续之前附加以下规则以允许新的SSH连接(根据需要调整端口):
-A TCP -p tcp --dport 22 -j ACCEPT
TCP和UDP链
TCP和UDP链包含用于接受新的传入TCP连接和UDP流到特定端口的规则。
打开端口到传入连接
要在Web服务器的端口80上接受传入TCP连接:
#iptables -A TCP -p tcp --dport 80 -j ACCEPT
要在Web服务器(HTTPS)的端口443上接受传入TCP连接:
#iptables -A TCP -p tcp --dport 443 -j ACCEPT
允许远程SSH连接(在端口22上):
#iptables -A TCP -p tcp --dport 22 -j ACCEPT
要在DNS服务器的端口53上接受传入的UDP流:
#iptables -A UDP -p udp --dport 53 -j ACCEPT
查看man iptables
更多高级规则,如匹配多个端口。
港口爆震
端口敲击是一种外部打开端口的方法,默认情况下,防火墙保持关闭。它通过要求连接尝试到一系列预定义的封闭端口来工作。当接收到正确的端口“敲击”序列(连接尝试)时,防火墙打开某些端口以允许连接。有关详细信息,请参阅港口爆破。
防止欺骗攻击
阻止来自互联网或本地网络的保留本地地址通常通过将rp_filter
sysctl中的(反向路径过滤器)设置为1.为此,请将以下行添加到您的/etc/sysctl.d/90-firewall.conf
文件中(有关详细信息,请参阅sysctl)以启用源地址验证内置于Linux内核本身。内核的验证将针对每种情况处理比个别iptables规则更好的欺骗。
net.ipv4.conf.all.rp_filter = 1
如果需要统计(和更好的日志记录),可以使用netfilter:
#iptables -t raw -I PREROUTING -m rpfilter --invert -j DROP
对于使用异步路由的特定设置,rp_filter=2
需要使用sysctl选项。将--loose
开关传递给rpfilter
模块将完成与netfilter相同的事情。
“隐藏”您的计算机
如果您正在运行桌面计算机,最好阻止一些传入请求。
阻止ping请求
“Ping”请求是发送到目的地址的ICMP分组,以确保设备之间的连接。如果您的网络工作正常,您可以安全地阻止所有ping请求。要注意,这是很重要的不给您发送的数据包将被拒绝,这样你就会仍处在一个IP范围的简单的nmap的“ping扫描”显示-实际上隐藏在您的计算机。
这是基本的“保护”,并使生活困难时调试问题在未来。你应该只为教育目的这样做。
要阻止回显请求,请将以下行添加到您的/etc/sysctl.d/90-firewall.conf
文件(有关详细信息,请参阅sysctl):
net.ipv4.icmp_echo_ignore_all = 1
更多信息在iptables的手册页,或阅读网页上的文档和示例http://www.snowman.net/projects/ipt_recent/
Tricking端口扫描仪
攻击者使用端口扫描来识别计算机上的打开端口。这允许他们识别和指纹你正在运行的服务,并可能针对他们发动攻击。
INVALID状态规则将处理除UDP,ACK和SYN扫描之外的每种类型的端口扫描(分别是nmap中的-sU,-sA和-sS)。
ACK扫描不用于标识打开的端口,而是用于标识由防火墙过滤的端口。由于对具有状态NEW的所有TCP连接的SYN检查,由ACK扫描发送的每个单个分组将被TCP RESET分组正确拒绝。一些防火墙丢弃这些数据包,这允许攻击者映射出防火墙规则。
最近的模块可以用来欺骗剩余的两种类型的端口扫描。最近的模块用于将主机添加到“最近”列表,可用于指纹和停止某些类型的攻击。可以查看当前最近的列表/proc/net/xt_recent/
。
SYN扫描
在SYN扫描中,端口扫描器向每个端口发送SYN数据包。封闭端口返回TCP RESET数据包,或者被严格的防火墙丢弃。打开的端口返回SYN ACK数据包,而不管防火墙是否存在。
最近的模块可用于跟踪具有拒绝连接尝试的主机,并返回它们发送到打开端口的任何SYN数据包的TCP重置,就像端口被关闭一样。如果打开的端口是第一个被扫描的端口,仍将返回SYN ACK,因此需要在非标准端口上运行诸如ssh等应用程序,以使其始终如一地工作。
首先,在TCP链的顶部插入一个规则。此规则用TCP RESET对过去六十秒内进入TCP-PORTSCAN列表的任何主机做出响应。该--update
开关使得最近的列表被更新,意味着60秒计数器被重置。
#iptables -I TCP -p tcp -m recent --update --seconds 60 --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
接下来,需要修改拒绝TCP分组的规则,以将具有被拒绝分组的主机添加到TCP-PORTSCAN列表。
#iptables -D INPUT -p tcp -j REJECT --reject-with tcp-reset
#iptables -A INPUT -p tcp -m recent --set --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
UDP扫描
UDP端口扫描类似于TCP SYN扫描,除了UDP是“无连接”协议。没有握手或致谢。相反,扫描器向每个UDP端口发送UDP数据包。Closed端口应返回ICMP端口不可达消息,并且打开的端口不返回响应。由于UDP不是“可靠”协议,因此扫描器无法知道数据包是否丢失,并且必须对不返回响应的每个端口执行多个检查。
Linux内核发出ICMP端口不可达消息的速度非常慢,因此针对Linux机器的完整UDP扫描将花费10个小时。但是,仍然可以识别公共端口,因此对SYN扫描使用与UDP扫描相同的对策是一个好主意。
首先,添加一条规则,以拒绝来自UDP-PORTSCAN列表中主机的数据包到UDP链的顶部。
#iptables -I UDP -p udp -m recent --update --seconds 60 --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
接下来,修改UDP的拒绝数据包规则:
#iptables -D INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
#iptables -A INPUT -p udp -m recent --set --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
还原最终规则
如果使用上述端口扫描技巧之一或两者,则最终默认规则不再是INPUT链中的最后一个规则。它需要是最后的规则,否则它会拦截你刚才添加的特技端口扫描器规则,它们将永远不会被使用。只需删除规则(-D),然后再次使用append(-A)将其添加到链的末尾。
#iptables -D INPUT -j REJECT --reject-with icmp-proto-unreachable
#iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
防止其他攻击
请参阅sysctl#TCP / IP堆栈硬化相关的内核参数。
暴力攻击
不幸的是,对通过外部IP地址可访问的服务的强力攻击是常见的。这样做的一个原因是,使用许多可用工具很容易进行攻击。幸运的是,有一些方法来保护服务免受他们。一个是使用适当的iptables
规则,其在设定数量的分组尝试发起连接之后激活和黑名单IP。另一个是使用专门的守护程序监视失败的尝试的日志文件和黑名单相应。
两个在密码失败过多之后禁止IP的程序包是Fail2ban或sshd
特别是Sshguard。这两个应用程序更新iptables规则以拒绝来自列入黑名单的IP地址的未来连接。
以下规则提供了一个示例配置,以减轻使用的SSH强力攻击iptables
。
#iptables -N IN_SSH
#iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH
#iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j DROP
#iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j DROP
#iptables -A IN_SSH -m recent --name sshbf --set -j ACCEPT
大多数选项应该是不言自明的,它们允许在十秒内三个连接包。在那段时间的进一步尝试将黑名单的IP。下一个规则通过在30分钟内允许总共四次尝试来添加一个怪癖。这是因为一些暴力攻击实际上执行得很慢,而不是一连串的尝试。规则采用了一些附加选项。要阅读有关它们的更多信息,请检查此示例的原始引用:compilefailure.blogspot.com
使用上述规则,现在确保:
#iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH
在iptables.rules文件中的适当位置。
这个安排适用于IN_SSH规则,如果你遵循了整个wiki到目前为止:
*:
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j IN_SSH
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
*:
上述规则当然可以用于保护任何服务,尽管保护SSH守护程序可能是最常用的一种。
保存规则
规则集现在完成,应该保存到您的硬盘驱动器,以便它可以在每次启动时加载。
systemd单元文件指向将保存规则配置的位置:
iptables = / etc / iptables / iptables.rules
ip6tables = / etc / iptables / ip6tables.rules
使用此命令保存规则:
#iptables-save> /etc/iptables/iptables.rules
并确保您的规则在启动时加载启用iptables systemd服务。
通过启动 iptables.service
,然后检查服务的状态,检查规则加载是否正确。
IPv6
如果你不使用IPv6(大多数ISP不支持它),你应该禁用它。
否则,应启用IPv6的防火墙规则。在复制IPv4规则作为基础之后:
#cp /etc/iptables/iptables.rules /etc/iptables/ip6tables.rules
第一步是将规则中引用的IP从IPv4格式更改为IPv6格式。
接下来,一些规则(作为本文中针对IPv4的示例构建)必须进行调整。IPv6获得了新的ICMPv6协议,取代了ICMP。因此,拒绝错误返回码--reject-with icmp-port-unreachable
并--reject-with icmp-proto-unreachable
必须转换为ICMPv6码。
RFC 4443中列出了可用的ICMPv6错误代码,它指定了防火墙规则应该使用的连接尝试--reject-with
。这样做将基本上通知远程系统连接被防火墙拒绝,而不是侦听服务。
icmp6-adm-prohibited
如果优选不明确通知防火墙过滤器的存在,则还可以拒绝该分组,而没有消息:
-A INPUT -j REJECT
上面将拒绝与默认返回错误--reject-with icmp6-port-unreachable
。您应该注意,识别防火墙是端口扫描应用程序的基本功能,大多数将识别它。
在下一步中,确保协议和扩展名更改为IPv6适用于有关所有新的传入ICMP回显请求(ping)的规则:
#ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT
Netfilter conntrack似乎不跟踪ICMPv6邻居发现协议(IPv6的等效ARP),因此我们需要允许ICMPv6流量,不管所有直接连接的子网的状态。在删除之后--ctstate INVALID
,但在任何其他DROP或REJECT目标之前插入以下内容,以及每个直接连接的子网的相应行:
#ip6tables -A INPUT -s fe80 :: / 10 -p icmpv6 -j ACCEPT
由于没有用于IPv6的内核反向路径过滤器,您可能需要在ip6tables中启用以下内容:
#ip6tables -t raw -A PREROUTING -m rpfilter -j ACCEPT
#ip6tables -t raw -A PREROUTING -j DROP
配置完成后,使该ip6tables服务,它的目的是在并行运行的iptables。
设置NAT网关
本指南的本部分涉及NAT网关。假定您已经阅读了指南的第一部分,并设置了INPUT,OUTPUT,TCP和UDP链,如上所述。到目前为止,所有规则都已在过滤器表中创建。在本节中,我们还将使用nat表。
设置过滤器表
创建必要的链
在我们的设置中,我们将使用过滤表中的另外两个链,fw-interfaces和fw-open链。使用命令创建它们
#iptables -N fw-interfaces
#iptables -N fw-open
设置FORWARD链
设置FORWARD链与第一部分中的INPUT链类似。
现在我们使用conntrack匹配设置一个规则,与INPUT链中的规则相同:
#iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
下一步是启用对可信接口的转发,并使所有数据包通过fw-open链。
#iptables -A FORWARD -j fw-interfaces
#iptables -A FORWARD -j fw-open
剩余的数据包被拒绝与ICMP消息:
#iptables -A FORWARD -j REJECT --reject-with icmp-host-unreachable
#iptables -P FORWARD DROP
设置fw-interfaces和fw-open链
当我们分别处理nat表中的POSTROUTING和PREROUTING链时,fw-interfaces和fw-open链的含义将在后面解释。
设置nat表
在本节中,我们假设出接口(具有公共互联网IP的接口)是ppp0。请记住,如果您的外出接口具有其他名称,则必须更改所有以下规则中的名称。
设置POSTROUTING链
现在,我们必须定义谁可以连接到互联网。假设我们有子网192.168.0.0/24(这意味着的形式192.168.0的所有地址。*)上的eth0。我们首先需要在FORWARD表中接受这个接口上的机器,这就是为什么我们在上面创建了fw-interfaces链:
#iptables -A fw-interfaces -i eth0 -j ACCEPT
现在,我们必须更改所有传出的数据包,以使它们具有我们的公共IP地址作为源地址,而不是本地LAN地址。为此,我们使用MASQUERADE目标:
#iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE
不要忘记上面的-o ppp0参数。如果你省略它,你的网络将被拧紧。
让我们假设我们在接口eth1上有另一个子网,10.3.0.0/16(意思是所有地址10.3。*。*)。我们再加上相同的规则:
#iptables -A fw-interfaces -i eth1 -j ACCEPT
#iptables -t nat -A POSTROUTING -s 10.3.0.0/16 -o ppp0 -j MASQUERADE
最后一步是启用数据包转发(如果尚未启用)。
来自这些子网的机器现在可以使用您的新NAT设备作为其网关。请注意,您可能想要设置DNS和DHCP服务器,如dnsmasq或bind和dhcpd的组合,以简化客户端计算机上的网络设置DNS解析。这不是本指南的主题。
设置PREROUTING链
有时,我们想要将来自网关的传入数据包的地址更改为LAN机器。要做到这一点,我们使用FW打开上面定义的链,以及在PREROUTING链中的NAT在以下两个简单的例子表。
首先,我们要将所有传入的SSH数据包(端口22)更改为机器192.168.0.5的ssh服务器:
#iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 22 -j DNAT --to 192.168.0.5
#iptables -A fw-open -d 192.168.0.5 -p tcp --dport 22 -j ACCEPT
第二个示例将向您展示如何将数据包更改为与传入端口不同的端口。我们要将端口8000上的任何传入连接更改为192.168.0.6端口80上的Web服务器:
#iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to 192.168.0.6:80
#iptables -A fw-open -d 192.168.0.6 -p tcp --dport 80 -j ACCEPT
相同的设置也适用于udp数据包。
保存规则
保存规则:
#iptables-save> /etc/iptables/iptables.rules
并确保在启动启用iptables systemd服务时加载您的规则。