1. 项目概述:从攻击视角理解防御
最近在复现一些经典的网络攻防场景,发现很多朋友对防火墙规则的理解还停留在“开端口、关端口”的层面。实际上,一个真正有效的防御策略,必须建立在对攻击手法有清晰认知的基础上。这次,我打算在Kali Linux这个“攻击者”常用的平台上,反过来扮演“防御者”的角色,用最经典的iptables工具,来模拟构建一套对抗SSH暴力破解和Ping洪水攻击的动态防火墙规则。
你可能会问,为什么用Kali?直接在CentOS或者Ubuntu上演示不更贴近生产环境吗?我的考虑是,Kali Linux预装了大量的安全测试工具,这让我们可以非常方便地在本机就发起模拟攻击,观察攻击流量,并实时调整防御策略,形成一个完整的“攻防闭环”实验环境。这比单纯地罗列几条iptables命令要有趣和深刻得多。通过这个实验,你不仅能学会如何配置防火墙,更能理解攻击是如何发生的,以及每条防御规则背后的设计逻辑。无论你是运维工程师、安全爱好者,还是正在学习网络安全的同学,这套从攻击到防御的实战推演,都能让你对网络边界安全有一个更立体的认识。
2. 实验环境搭建与核心思路
2.1 实验环境规划与准备
工欲善其事,必先利其器。我们先来明确并搭建实验环境。我使用的是VMware Workstation 17 Pro,创建了一台Kali Linux虚拟机。这里的关键点在于网络配置。为了模拟最真实的攻防场景,我建议将虚拟机的网络适配器设置为“桥接模式”。这样,你的Kali虚拟机将和你宿主机在同一个局域网内,拥有一个独立的IP地址,可以完全模拟一台独立的主机进行网络通信。如果你使用NAT模式,虽然也能上网,但一些涉及外部网络访问的测试可能会受到虚拟网络结构的限制。
安装好Kali后,第一件事是更新系统并安装必要的工具。打开终端,执行:
sudo apt update && sudo apt upgrade -y sudo apt install -y iptables-persistent net-toolsiptables-persistent这个包非常重要,它提供了netfilter-persistent服务,能帮助我们保存iptables规则,使其在系统重启后依然生效。否则,你精心配置的规则重启后就消失了。
接下来,我们需要确保SSH服务是开启的,因为我们要把它作为被攻击的目标。Kali默认可能没有开启SSH,执行以下命令:
sudo systemctl enable ssh sudo systemctl start ssh sudo systemctl status ssh看到“active (running)”状态就说明成功了。记下你Kali虚拟机的IP地址,使用ip a或ifconfig命令查看。
注意:在实验开始前,请务必确认你的操作环境是隔离的虚拟机或专属测试网络。绝对不要在生产服务器或任何公共网络中进行此类攻击模拟,以免触发真实的安全警报或对他人的服务造成影响。
2.2 防御策略的核心设计思路
面对SSH爆破和Ping洪水这两种截然不同的攻击,我们的防御策略也需要“分而治之”。
对于SSH暴力破解,攻击者的特征是:在短时间内,从一个或多个源IP,向你的22端口发起大量、高频的TCP连接尝试,并使用不同的用户名密码组合进行认证。防御的核心思路不是完全阻断,而是“异常行为识别与动态封禁”。我们无法预知哪个IP是攻击者,但我们可以定义“异常”:比如,在60秒内,对22端口的连接尝试超过5次,这很可能就是爆破行为。iptables的recent模块正是为此而生,它可以动态地维护一个“黑名单”,将符合异常条件的IP地址临时加入其中,在一段时间内拒绝其所有访问。
对于Ping洪水攻击,其本质是ICMP协议层面的流量泛洪。攻击者发送海量的ICMP Echo Request(ping请求)包,耗尽目标的网络带宽或处理资源。防御这种攻击的思路更直接:限速。我们允许正常的ping检测(比如每秒几个包),但坚决限制单位时间内通过的ICMP包数量,将超过阈值的流量直接丢弃。iptables的limit模块可以完美实现基于令牌桶的流量速率限制。
总结一下我们的战术:用recent模块对付SSH爆破(动态黑名单),用limit模块对付Ping洪水(流量整形)。接下来,我们就进入具体的规则配置环节。
3. iptables规则链结构与基础配置解析
在动手写规则之前,必须对iptables的基本框架有个清晰的认识,否则规则顺序一错,满盘皆输。iptables通过“表”、“链”、“规则”三层结构来组织功能。
表:定义了规则的用途。我们最常用的是filter表(负责过滤)和nat表(负责地址转换)。本次实验我们只操作filter表。链:数据包流经的检查点。filter表内置三条链:
- INPUT:处理发往本机的数据包。我们的防御规则主要就加在这里。
- FORWARD:处理经过本机路由转发的数据包(网关/路由器角色)。本次实验不涉及。
- OUTPUT:处理从本机发出的数据包。
数据包的旅程是这样的:当一个外部ping包或SSH连接请求到达你的Kali机器时,它首先会进入INPUT链。链中的规则按从上到下的顺序逐一匹配。一旦匹配成功,就执行该规则定义的动作(如ACCEPT接受、DROP丢弃、REJECT拒绝),并且不再继续匹配后续规则。如果所有规则都不匹配,则执行该链的默认策略。
因此,规则的顺序至关重要。一个经典的最佳实践是:先设置默认策略为DROP(拒绝所有),然后创建“白名单”规则,放行必要的流量。但为了实验清晰,我们先从宽松策略开始,最后再收紧。首先,我们清空所有现有规则并设置默认策略为ACCEPT,避免一开始就把自己锁在外面:
sudo iptables -F # 清空所有链中的规则 sudo iptables -X # 删除用户自定义的链 sudo iptables -Z # 清零所有链的计数器 sudo iptables -P INPUT ACCEPT sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT接着,我们创建一些无论如何都应该放行的基础规则,这些规则应该放在最前面,因为它们匹配的是我们确信无害的流量:
# 1. 允许本地回环接口(lo)的所有流量,这是系统内部通信必需的 sudo iptables -A INPUT -i lo -j ACCEPT # 2. 允许所有已建立连接及相关连接的数据包通过。这是关键! # 它确保了由本机主动发起的连接(如浏览网页)的返回数据包不会被阻断。 sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT-m state --state ESTABLISHED,RELATED这条规则是防火墙的“文明之窗”。没有它,你即使能发出请求,也收不到任何回复,网络体验会瞬间崩塌。把它放在靠前的位置,能极大提升效率,因为大多数流量都属于已建立的连接。
4. 对抗SSH暴力破解:动态黑名单实战
现在,我们来构建防御SSH爆破的核心规则。我们将使用recent模块来追踪和封禁可疑IP。
4.1 理解recent模块的工作机制
recent模块可以维护一个或多个动态IP列表(如SSH_ATTACKER),并提供了丰富的操作:
--set:将匹配到的数据包的源IP地址加入指定列表。--update:更新该IP在列表中的时间戳(用于判断是否在时间窗口内)。--rcheck:检查源IP是否在列表中。--seconds:与上述操作结合,限定一个时间窗口。--hitcount:在时间窗口内,匹配到的次数。
我们的策略设计如下:
- 当一个新的IP尝试连接SSH端口(22)时,我们将其记录到
SSH_ATTACKER列表(--set)。 - 随后,检查该IP在过去的60秒内,是否是第2次(或更多次)尝试连接SSH(
--rcheck --seconds 60 --hitcount 2)。如果是,则立即丢弃该包,并跳转到一条专门的“封禁”规则。 - 封禁规则将拒绝该IP的所有后续访问,并记录日志。
4.2 逐步配置SSH防御规则
让我们一行行来配置,并理解每一行的意图:
# 步骤1:创建一条独立的链来管理SSH相关规则,使结构更清晰 sudo iptables -N SSH_PROTECT # 步骤2:在SSH_PROTECT链中,定义核心检测逻辑 # 规则2.1:如果IP在60秒内尝试连接SSH超过5次,则将其加入黑名单并记录日志 sudo iptables -A SSH_PROTECT -m recent --name SSH_ATTACKER --update --seconds 60 --hitcount 5 -j LOG --log-prefix "[IPTABLES SSH BLOCK]: " sudo iptables -A SSH_PROTECT -m recent --name SSH_ATTACKER --update --seconds 60 --hitcount 5 -j DROP # 规则2.2:对于新的SSH连接尝试,将其源IP记录到SSH_ATTACKER列表 sudo iptables -A SSH_PROTECT -m recent --name SSH_ATTACKER --set -j ACCEPT # 步骤3:将SSH流量导向我们自定义的SSH_PROTECT链进行处理 # 这条规则插入到INPUT链的靠前位置(在基础放行规则之后,其他规则之前) sudo iptables -I INPUT 3 -p tcp --dport 22 -j SSH_PROTECT规则解读与顺序的重要性:
- 规则2.1和2.2的顺序不能颠倒。必须先检查是否超限(
--update),再执行记录(--set)。如果反了,那么第一次连接就会被--set记录,紧接着--update检查时,它发现自己已经在列表里且hitcount至少为1,这可能导致合法用户的第一次连接就被误判。 - 我们的参数是
60秒内5次。这个阈值可以根据你的服务器公开程度和日志分析来调整。对于暴露在公网的服务器,可以更严格(如60秒3次);对于内网测试,可以宽松些。 -j LOG规则用于在系统日志(通常是/var/log/kern.log或/var/log/syslog)中记录被封禁的尝试,便于事后审计。生产环境建议开启。
4.3 模拟攻击与验证效果
规则配好了,效果如何?我们开另一个终端窗口来模拟攻击。使用hydra这个Kali自带的强大爆破工具进行测试。请确保你攻击的目标IP是你自己的Kali虚拟机IP。
快速测试命令(使用一个很小的用户密码字典做演示):
# 假设你的Kali IP是 192.168.1.100 # 此命令尝试用root用户和几个常见密码进行爆破,速度很快。 hydra -l root -P /usr/share/wordlists/fasttrack.txt 192.168.1.100 ssh -t 4-t 4表示使用4个并行任务,加快尝试速度。很快,你应该能看到尝试失败的记录。
此时,查看你的防火墙日志和recent列表:
# 查看封禁日志 sudo tail -f /var/log/kern.log | grep "IPTABLES SSH BLOCK" # 查看当前的SSH_ATTACKER列表 sudo cat /proc/net/xt_recent/SSH_ATTACKER在日志中,你会看到类似[IPTABLES SSH BLOCK]前缀的记录,显示了被DROP的数据包信息。在/proc/net/xt_recent/SSH_ATTACKER文件中,你会看到被加入列表的IP地址及其最新访问时间戳。
现在,尝试从被封锁的IP(就是你运行hydra的宿主机)再次SSH连接Kali,会发现连接超时或被拒绝,而来自其他未触发规则的IP的连接则不受影响。这就是动态黑名单在起作用。
实操心得:
recent模块的列表存储在内存中,重启后会消失。这就是为什么之前要安装iptables-persistent。但即使服务重启,动态封禁的IP也会丢失。对于需要持久化封禁的恶意IP,应考虑结合ipset工具,将IP加入一个持久的集合,并用iptables引用该集合进行DROP。
5. 抵御Ping洪水攻击:ICMP流量限速实战
Ping洪水攻击旨在耗尽带宽或系统资源。我们的防御目标是:允许正常的、低频率的ping(用于网络诊断),但坚决限制高速率的ping请求。
5.1 使用limit模块进行流量整形
limit模块使用令牌桶算法。你可以把它想象成一个水龙头和一个水桶。水龙头以固定的速率(如--limit 1/second)向桶里滴水(令牌)。每个数据包需要从桶里舀走一滴水(一个令牌)才能被放行。如果桶是空的,数据包就被丢弃。
我们为ICMP Echo Request(ping请求)类型的数据包设置一个速率限制。
# 步骤1:允许正常的、低频率的ping # 限制每秒最多通过3个ICMP Echo Request包(--limit 3/second),突发峰值允许达到5个(--limit-burst 5) sudo iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 3/second --limit-burst 5 -j ACCEPT # 步骤2:丢弃所有超出限制的ping请求 # 这条规则没有`-m limit`,它会匹配上所有未被上一条规则接受的echo-request包(即超限的包) sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP规则解读:
--limit 3/second:平均速率限制为每秒3个包。这是一个比较宽松的值,正常网络诊断完全够用。--limit-burst 5:令牌桶的初始容量和最大容量是5。这意味着,在长时间没有ping之后,突然来的前5个ping包会被立刻放行(消耗初始令牌),从第6个开始,就必须遵循每秒3个的速率限制。- 规则顺序:必须先放行符合限速的包(
-j ACCEPT),再丢弃所有剩余的此类包(-j DROP)。因为iptables规则是顺序执行的,一旦包被第一条规则接受,就不会再匹配第二条。
5.2 模拟攻击与效果验证
我们可以用ping命令的洪水模式来测试。在宿主机或其他机器上,向Kali虚拟机发起高速ping:
# 在攻击机器上执行,-f 参数表示洪水模式(flood),会以尽可能快的速度发送ping包 ping -f 192.168.1.100或者使用更专业的hping3工具(Kali自带):
sudo hping3 --icmp --flood 192.168.1.100回到Kali虚拟机,打开终端,实时监控ICMP包的接收情况:
# 使用 tcpdump 抓取ICMP包,观察速率 sudo tcpdump -i eth0 icmp and icmp[icmptype]==icmp-echo你会发现,尽管攻击端在疯狂发送,但Kali端接收到的ICMP Echo Request包的速率被稳定地限制在了大约每秒3个左右。同时,你可以通过watch命令动态查看iptables对这条规则的匹配计数:
watch -n 1 'sudo iptables -L INPUT -v -n | grep -A2 -B2 echo-request'在输出中,你会看到第一条ACCEPT规则的pkts计数器缓慢增长(约3/秒),而第二条DROP规则的pkts计数器飞速增长,所有超限的包都被丢弃了。
6. 规则优化、持久化与高级策略
6.1 规则顺序优化与默认策略收紧
目前,我们的INPUT链规则顺序大致是:
- 放行本地回环。
- 放行已建立连接。
- SSH动态防护规则。
- ICMP限速规则。
- 默认策略是ACCEPT。
这存在一个安全隐患:除了我们明确处理的SSH和ICMP,其他所有端口和服务(如未关闭的HTTP、FTP等)都对外完全敞开。作为安全加固的最后一步,我们应该将默认策略改为DROP,并只放行必要的服务。
假设我们只需要SSH(22端口)和后续可能用于管理的HTTPS(443端口),那么增加规则并修改策略:
# 在INPUT链末尾(在ICMP DROP规则之后)增加以下规则 # 放行特定的、必要的入站服务端口 sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT # SSH (实际上已被前面的SSH_PROTECT链处理,这里显式放行最终通过的) sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS # 最后,将INPUT链和FORWARD链的默认策略设置为DROP # 注意:一定要确保OUTPUT链策略为ACCEPT,否则本机无法对外发起连接。 sudo iptables -P INPUT DROP sudo iptables -P FORWARD DROP # OUTPUT策略保持ACCEPT # sudo iptables -P OUTPUT ACCEPT重要警告:在执行sudo iptables -P INPUT DROP之前,必须确保你当前是通过SSH连接的会话不是唯一的活跃会话,或者你直接在虚拟机本地终端操作。否则,一旦规则生效,你可能会立刻断开SSH连接并被锁在外面!一个安全的做法是使用at命令设置一个定时任务,在几分钟后执行修改默认策略的命令,给你留下测试和回滚的时间窗口。
6.2 配置持久化保存
内存中的规则重启即失效。使用之前安装的iptables-persistent来保存:
# 保存IPv4规则 sudo netfilter-persistent save # 或直接使用 iptables-save 导出到文件,再由 persistent 服务加载 sudo sh -c 'iptables-save > /etc/iptables/rules.v4'保存后,重启系统或重启netfilter-persistent服务,规则会自动加载:
sudo systemctl restart netfilter-persistent6.3 进阶策略探讨
结合ipset管理大规模IP黑名单:
recent模块适合动态、短期的封禁。如果你有一个已知的恶意IP列表(例如从威胁情报平台获取),使用ipset会更高效。你可以创建一个IP地址的哈希集合,然后在iptables规则中匹配这个集合,一条规则就能封禁成千上万个IP,对性能影响极小。sudo apt install ipset sudo ipset create malicious_ips hash:ip sudo ipset add malicious_ips 1.2.3.4 sudo iptables -I INPUT -m set --match-set malicious_ips src -j DROP记得也要保存
ipset规则。使用日志分析工具联动:更高级的防御可以结合
rsyslog或systemd-journald收集防火墙日志,然后使用fail2ban或自定义脚本进行分析。当发现某个IP在短时间内触发了多种攻击规则(如SSH爆破+Web扫描),可以自动将其IP加入ipset永久黑名单,实现智能化的主动防御。应对慢速攻击:聪明的攻击者可能会把SSH尝试频率降低到每分钟一次,从而绕过我们“60秒5次”的规则。应对这种“慢速爆破”,需要调整时间窗口和阈值,或者使用更复杂的异常检测算法,这通常需要借助
fail2ban这类工具更灵活的配置。
7. 常见问题、排查技巧与实验复盘
7.1 规则不生效?排查步骤实录
- 检查规则顺序:使用
sudo iptables -L INPUT -v -n --line-numbers查看规则列表和顺序。记住,数据包是从上到下匹配的,第一条匹配的规则决定其命运。确保你的放行规则(如已建立连接、特定端口)在拒绝规则之前。 - 查看计数器:上述命令中的
pkts和bytes列显示了每条规则匹配到的数据包和字节数。如果你预期的规则计数器没有增加,说明数据包被前面的规则匹配走了。 - 检查协议和端口:确认你写的协议(
-p tcp/udp/icmp)和目标端口(--dport)是否正确。例如,SSH是TCP 22端口。 - 确认链和表:确保规则添加到了正确的链(
INPUT/OUTPUT/FORWARD)和表(默认是filter表)中。使用sudo iptables -t nat -L可以查看其他表。 - 模拟测试:在Kali本机,可以用
telnet或nc测试端口连通性,用ping测试ICMP,这有助于排除网络层面的问题。telnet localhost 22 # 测试本机SSH端口 ping -c 4 127.0.0.1 # 测试本机环回ICMP
7.2 把自己锁在外面了怎么办?
这是新手常踩的坑。如果你在远程SSH会话中配置防火墙,不小心阻断了自己,可以按以下步骤恢复:
- 前提:你还有物理或虚拟控制台(VMware/VirtualBox的图形界面)的访问权限。
- 方法:通过虚拟机控制台登录,直接清空或重置防火墙规则。
sudo iptables -F # 清空规则 sudo iptables -P INPUT ACCEPT # 恢复默认策略 sudo iptables -P FORWARD ACCEPT # 检查并保存 sudo netfilter-persistent save - 教训:永远在本地终端或一个有“逃生通道”的环境下进行防火墙重大修改。使用
at命令延迟执行高风险操作是很好的习惯。
7.3 实验复盘与核心收获
通过这个从攻击到防御的完整实验,我们不仅仅是敲了几行iptables命令,更重要的是建立了一种动态的、基于异常行为的防御思维。iptables不是一堵静态的墙,而是一个可以编程的、智能的流量过滤器。
核心收获:
- INPUT链是防御入口:对于服务器,精心设计INPUT链规则是安全基石。
- 状态跟踪是基础:
-m state --state ESTABLISHED,RELATED规则必须优先。 - 模块化是利器:
recent用于状态追踪和动态封禁,limit用于流量整形,ipset用于管理大规模集合。 - 顺序决定命运:规则的排列顺序直接决定过滤逻辑,务必谨慎。
- 日志是眼睛:关键拒绝规则加上
-j LOG,事后排查和攻击分析全靠它。 - 持久化是保障:配置完一定要保存,否则前功尽弃。
防火墙配置没有银弹,需要根据实际业务流量模式不断调整阈值和规则。最好的学习方式就是像我们今天这样,在一个安全的实验环境中,主动发起攻击,观察流量,然后设计并验证防御规则。这种攻防对抗的视角,能让你对网络安全有更深刻、更直观的理解。