外观
防火墙技术基础与iptables实战
约 11061 字大约 37 分钟
网络安全技术防火墙iptables包过滤
2026-05-19
第 15 课:防火墙技术基础与iptables实战 项目十五
本课核心
上一课你搭了一条 VPN 隧道,把总部和分支连了起来。现在隧道建好了,新的问题马上来了:什么流量允许通过,什么流量必须拦下来?
你不能因为连了 VPN,就让分支的所有流量无限制地访问总部的所有服务器。财务部的服务器只允许财务人员访问,代码仓库只允许研发网段的 IP,对外服务的 Web 服务器可以和公网通信但绝不能主动访问内网数据库。这些规则谁来执行?防火墙。
本课不做纸上谈兵——你会在 Linux 上用 iptables 亲手写过滤规则,控制哪个 IP 能访问哪个端口、限制 ping 的频率防止 DoS、配置 NAT 让内网主机上网、设计一个包含 DMZ 的三区安全架构。你写的每一条规则,都能用 ping、curl、nmap 立即验证生效。
课堂红线
本课所有实验都在本机 Kali 上用 iptables 操作本地网络栈。禁止将实验规则应用到生产服务器,禁止用课堂学到的技术绕过他人系统的防火墙策略,禁止对未经授权的目标进行端口扫描。
一、 没有防火墙的网络,就像没有门禁的大楼
回顾一下前面两课你搭建的东西:OpenVPN 隧道把远程办公室和总部内网连了起来,AES-GCM 加密保证了公网链路上数据不会被偷看。但请你想一个问题——
分支的 10.88.0.2 这台电脑,连上 VPN 之后,它能不能访问总部的财务数据库?能不能 SSH 到总部的核心交换机?能不能对总部的服务器发起端口扫描?
如果答案都是"能",那这条 VPN 隧道就不是安全通道,而是一根直捅进总部的吸管。任何一个分支终端中毒,攻击者就能顺着隧道访问总部的一切。
防火墙要做的就是三件事:
第一,决定谁可以过。 源 IP 是哪个、目的 IP 是哪个、协议是 TCP 还是 UDP、端口是 80 还是 22——这些组合起来叫"五元组"。防火墙按五元组匹配规则,命中了就执行动作:放行(ACCEPT)、丢弃(DROP)、还是拒绝并通知对方(REJECT)。
第二,跟踪连接状态。 你访问百度,你的浏览器向百度 443 端口发了一个 SYN 包。百度回复的 SYN-ACK 包源端口是 443、目的端口是你浏览器的随机高端口——如果防火墙只做静态规则匹配,你还要为每一个回包单独写一条放行规则。这显然不可能。状态检测防火墙会记住"你刚才发了一个 SYN 出去",然后自动放行匹配的回包。这就是 SPI 的核心价值。
第三,隐藏内网结构。 内网主机用的是私有 IP(192.168.x.x、10.x.x.x),公网不认识它们。防火墙做 NAT,把内网主机的源 IP 替换成防火墙自己的公网 IP,外网服务器只看到防火墙在和它通信,看不到内网有几台机器、IP 是多少。
这三个功能串在一起:访问控制 → 状态跟踪 → 地址转换,就是一个企业防火墙的标准工作流。
防火墙的"位置感":安全域划分
防火墙最核心的设计决策,不是"用什么品牌",而是把它放在哪、它分隔了谁。
一个最小的企业网络,至少应该分成三个安全域:
互联网侧:不可信。 只开放必要的服务端口(如 Web 服务器的 80/443),其余全部拒绝。而且这个"开放"不是把服务器直接暴露在公网,而是做 DNAT——公网 IP 的 80 端口映射到 DMZ 里某台 Web 服务器的内网 IP。
DMZ 区:半可信。 放 Web 服务器、邮件服务器、DNS 服务器——这些需要被公网访问,但绝不能让它们反过来访问内网的数据库和文件服务器。即使 Web 服务器被攻破,攻击者也被困在 DMZ 里,到不了内网核心系统。
内网区:可信但受限。 员工办公、研发、财务系统都在这里。公网不能主动访问内网,内网主机通过 SNAT 上网。内网内部还要按部门继续细分——研发部和财务部之间再加访问控制。
这个"三区模型"是你在安全面试和安全方案设计里最常被问到的基础架构。它不是标准答案(大企业可能有七八个安全域),但它是所有安全域划分的起点。
🚧 互动实验:防火墙安全域策略 (Security Zones)
企业防火墙通常将网络划分为不同安全级别的区域 (如 Trust、DMZ、Untrust)。不同区域间的默认访问策略决定了流量是否能通行。
📜 预设安全策略表:
1. Trust ➡️ 任何区域:允许 (Allow)
2. Untrust ➡️ DMZ:允许 HTTP/HTTPS 端口
3. DMZ ➡️ Trust:拒绝 (Deny)
4. 其他所有未明确允许的流量:默认拒绝 (Default Drop)
Trust (高信誉)
💻 内部办公 PC
🧱 NGFW
DMZ (中信誉)
🌍 对外 Web 服务器
Untrust (极低信誉)
😈 互联网黑客/用户
等保 2.0 对防火墙的要求(扩展阅读)
网络安全等级保护 2.0 在"安全区域边界"层面明确要求:
- 三级系统必须在网络边界部署访问控制设备,启用访问控制功能。
- 访问控制的粒度应达到端口级。
- 应能根据会话状态信息为数据流提供明确的允许/拒绝访问的能力(即 SPI)。
- 应在网络边界对恶意代码进行检测和清除。
这意味着:你在本课学的 iptables 五元组过滤 + 状态检测,就是等保测评里"边界防护"控制点的核心内容。将来你如果在等保测评机构工作,测评师会逐条检查防火墙的策略配置——不是只看"有没有防火墙",而是看策略粒度够不够细。
二、 防火墙的三代演进:从包过滤到智能识别
防火墙不是一成不变的技术。过去三十多年,它经历了三代演进:
第一代:静态包过滤
只看每个数据包的包头——源 IP、目的 IP、协议、源端口、目的端口。每个包独立判断,不记得前面有没有相关的包。优点是速度快、资源消耗小。缺点也很致命:它不理解"连接"的概念。如果你允许内网访问外网 80 端口,你必须同时允许外网 80 端口向内网任意高端口发数据(因为 HTTP 回包就是这样的),这就等于在防火墙上开了一个巨大的洞。
第二代:状态检测(SPI)
核心改进就是"记住连接"。当一个内网主机向外网服务器的 80 端口发了一个 SYN 包(第一个握手包),防火墙在连接跟踪表里记录一条:内网IP:随机端口 → 外网IP:80,状态=NEW。当外网的 SYN-ACK 回包到达时,防火墙查连接表,发现"哦,这是刚才那个连接的回复",自动放行。连接关闭或超时后,记录自动删除。
状态检测解决了静态包过滤最大的痛点——不需要为每个回包手工写规则。而且它还能防御一些基本攻击:比如一个 TCP 包声称自己是"已建立连接"的一部分但连接跟踪表里根本没有这个连接,那就直接丢弃——这是简单的反欺骗。
Linux 内核的 netfilter 框架就是经典的状态检测实现。你等一下用 iptables 写规则时,-m state --state ESTABLISHED,RELATED 这行配置就是在用状态检测。
🛡️ 互动实验:状态检测防火墙 (SPI) vs 无状态包过滤
外网恶意的 SYN-ACK 扫描可以轻易穿透“无状态包过滤”防火墙,但会被“状态检测防火墙”拦截。请尝试切换模式并发送不同数据包观察结果。
规则:仅允许 源端口=80 或 标志位=ACK 的包进入。不记录连接历史。
内网主机 (Client)
🧱
防火墙
连接跟踪表 (Conntrack)
该模式下未启用
外网服务器 / 攻击者
第三代:应用识别 + IPS + 威胁情报(NGFW)
状态检测能识别"这是 HTTP 流量",但不知道"这个 HTTP 请求里有没有 SQL 注入"。传统防火墙工作在 OSI 第 3~4 层(IP 和 TCP/UDP),下一代防火墙扩展到第 7 层(应用层)。
NGFW 能做的事情包括:
- 识别 8000 多种应用(不仅仅是"端口 80=HTTP",还能区分出"端口 80 上跑的是正常网页浏览还是迅雷下载")
- 内置 IPS 引擎,实时检测并阻断漏洞利用、恶意软件通信、C2 回连
- 关联威胁情报,自动封禁已知的恶意 IP
- 对 HTTPS 流量做 SSL 解密检查(中间人方式,需要在客户端安装企业 CA 证书)
本课先专攻前两代——你把 iptables 玩透了,理解 NGFW 的高级功能才有根基。第 16 课再专门讲应用层防火墙(WAF)和 NGFW。
防火墙的四种网络部署模式
防火墙不只是"放哪"的问题,还要决定它以什么方式嵌进网络。不同的部署模式决定了流量怎么经过防火墙、防火墙能看到什么信息。
路由模式(Routed Mode): 防火墙充当一个三层路由器,两张网卡分别配不同网段的 IP,流量在三层转发。这是最常见的部署方式——防火墙就是内外网的"闸门"。优点是能做完全的 NAT 和路由控制,缺点是所有流量必须经过防火墙,吞吐量瓶颈在这里。你前面实验里写的 FORWARD 链规则,就是在路由模式下工作的。
透明模式(Transparent Mode): 防火墙像一座桥——两张网卡没有 IP,在二层转发帧。对网络中的其他设备来说,防火墙完全"隐形"——交换机不知道它存在,ARP 表不变,路由表不用改。透明模式的好处是你可以把防火墙塞进已有的网络中,不改变任何 IP 规划。缺点是不能做 NAT(因为没有 IP),功能受限。iptables 通过 br_netfilter 内核模块支持桥接过滤——用 ebtables 在二层做访问控制。
混合模式(Mixed Mode): 部分接口工作在三层(路由模式),部分接口工作在二层(透明模式)。比如外网口做路由模式走 NAT,DMZ 口做透明模式桥接——同一个防火墙两种身份。企业级硬件防火墙通常支持这种部署。
虚拟线模式(Virtual Wire / Wire Mode): 防火墙的两张网卡在二层转发,但它还做应用层检测——看 HTTP 载荷、匹配 IPS 签名。这种模式下防火墙是一个"带检测的网线",连 MAC 地址都不改。常用于旁路 IPS 部署:交换机把流量镜像一份给防火墙分析,防火墙发现有攻击时另外发 RST 包去阻断。
什么是"旁路"和"串联"?
防火墙部署有两个基本位置选择:
串联(Inline): 防火墙串在链路中间,所有流量物理上必须经过它。优点是能实时阻断攻击——看见恶意流量直接丢。缺点是单点故障——防火墙挂了全网断。所以串联部署通常要求双机热备。
旁路(Out-of-Band / TAP): 防火墙挂在交换机镜像口上,只收流量、不发流量。优点是即使防火墙宕机也不影响网络。缺点是只能检测不能实时阻断——发现攻击后通过发送 RST 包或调用交换机 API 来间接阻断,有延迟。
三、 iptables 动手实验:规则不是"看"懂的,是"测"懂的
iptables 是 Linux 内核 netfilter 框架的用户态管理工具,也是你理解防火墙原理的最好教具——每一条规则怎么写、怎么生效、优先级怎么排,都在命令行里一目了然。
先记住 iptables 的骨架:
iptables -t 表名 -A 链名 匹配条件 -j 动作
│ │ │ │
│ │ │ └── 匹配后做什么:ACCEPT/DROP/REJECT/LOG
│ │ └── 源IP、目的IP、协议、端口、状态……
│ └── INPUT(进本机)/ OUTPUT(出本机)/ FORWARD(转发)
└── filter(过滤,默认)/ nat(地址转换)/ mangle(修改包头)三张表,五条链,构成了 iptables 的全部骨架。 本课只聚焦 filter 表的三条链(INPUT、OUTPUT、FORWARD),nat 表在实验三里用到。
🔄 互动演示:iptables 数据包流转 (Netfilter 框架)
选择不同的流量场景,观察数据包在内核中依次经过哪些“链”(Chains)。理解这个流程,才能知道把规则写在哪个链上。
外部网络 (In)
⬇️
PREROUTING 链
目的地址转换 (DNAT)
⬇️
路由判断 (目标是本机吗?)
↙️ 是
INPUT 链
入站规则过滤
⬇️
本机应用程序 (进程)
↘️ 否
FORWARD 链
转发规则过滤
⬇️
⬇️ 发出
路由判断 (决定出口)
⬇️
OUTPUT 链
出站规则过滤
↘️
↙️
POSTROUTING 链
源地址转换 (SNAT)
⬇️
外部网络 (Out)
📝 当前动作说明:数据包从网卡进入防火墙
实验一:用 iptables 保护本机——阻止特定 IP 访问 SSH
场景:你的服务器开着 SSH(22 端口),但你发现 192.168.1.100 这台机器在暴力破解你的密码。用 iptables 把它封掉。
# 实验前先保存当前规则,方便恢复。查看现有规则确认初始状态
sudo iptables -L -n -v --line-numbers
# 禁止来自 192.168.1.100 的所有流量进入本机
# -I INPUT 1:把规则插到 INPUT 链最前面(优先级最高)
# -s:源 IP -j DROP:匹配后直接丢弃,不回复任何信息
sudo iptables -I INPUT 1 -s 192.168.1.100 -j DROP
# 验证规则已生效——从被封锁的 IP(或本机模拟)尝试 ping/ssh 应失败
# 用另一台机器或本机测试:ping 192.168.1.100 应该不通
# 如果只想封锁 SSH 而不影响 ping,加上 -p tcp --dport 22
sudo iptables -D INPUT 1 # 先删掉上面那条全封规则
sudo iptables -A INPUT -s 192.168.1.100 -p tcp --dport 22 -j DROP # 只封锁 TCP 22 端口
# 实验完毕,清空所有规则恢复初始状态
sudo iptables -F验证方法: 从 192.168.1.100(或本机 curl/telnet)尝试连接 22 端口。规则生效后,连接应该超时(DROP 不回复,对方不知道是被拒绝还是网络不通)。如果改成 -j REJECT,对方会立即收到 "Connection refused"。
真实输出(2026-05-20,本机 Kali WSL):
# iptables --version
iptables v1.8.13 (nf_tables)
# iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
# iptables -I INPUT 1 -s 192.168.1.100 -j DROP
# iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 DROP all -- * * 192.168.1.100 0.0.0.0/0
# iptables -D INPUT 1
# iptables -A INPUT -s 192.168.1.100 -p tcp --dport 22 -j DROP
# iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 DROP tcp -- * * 192.168.1.100 0.0.0.0/0 tcp dpt:22实验二:状态检测——只放行"我自己发起的连接"的回包
这是理解 SPI 最直观的实验:写三条规则,实现"内网可以主动访问外网,外网不能主动访问内网"。
# 先清空所有规则
sudo iptables -F
# 规则 1:允许所有已建立连接和相关连接的流量进入
# ESTABLISHED:这个包属于一个已经完成握手的连接(比如回包)
# RELATED:这个包是由一个已有连接触发的新连接(比如 FTP 的数据通道)
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 规则 2:允许本地回环接口的流量(本机自己访问自己,很多服务依赖它)
sudo iptables -A INPUT -i lo -j ACCEPT
# 规则 3:拒绝所有其他进入流量(兜底规则)
# 把 INPUT 链的默认策略改为 DROP——所有没被前面规则匹配的包全部丢弃
sudo iptables -P INPUT DROP
# 验证:现在你可以从本机 ping 外网(例如 223.5.5.5),回包能进来
# 但如果别人从外网 ping 你,收不到回复——因为进来的 ICMP echo request 不匹配任何规则
ping -c 2 223.5.5.5 # 应该通——因为你的 ping 请求发出的回包匹配 ESTABLISHED
# 如果你在 OUTPUT 链不做限制,本机发起的所有出站连接都是允许的
# 但进入的包只有"回复"才能进来——这就是状态防火墙的核心逻辑
# 实验完毕恢复
sudo iptables -F
sudo iptables -P INPUT ACCEPT真实输出(2026-05-20,本机 Kali WSL):
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -i lo -j ACCEPT
# iptables -P INPUT DROP
# iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
# ping -c 2 -W 2 223.5.5.5
PING 223.5.5.5 (223.5.5.5) 56(84) bytes of data.
64 bytes from 223.5.5.5: icmp_seq=1 ttl=53 time=17.4 ms
64 bytes from 223.5.5.5: icmp_seq=2 ttl=53 time=17.7 ms
--- 223.5.5.5 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 17.400/17.537/17.674/0.137 ms这里有个容易搞混的点: -P INPUT DROP 是把 INPUT 链的默认策略设为 DROP,意思是"如果数据包走完了整条 INPUT 链、没有匹配到任何一条规则,就执行默认策略——丢弃"。它不是"把 INPUT 链上的规则全删了"(那是 -F)。默认策略相当于链的"兜底处理"。
实验三:NAT——让内网主机上网,把内网服务映射到公网
NAT 分为两种方向,很多人学了就混。你先记住:
- SNAT:改源地址。用于"内网主机访问外网"。防火墙把内网 IP 替换成自己的公网 IP,外网服务器只看到防火墙。回包到防火墙后,防火墙查 NAT 表,还原成内网 IP 送回内网主机。
- DNAT:改目的地址。用于"外网访问内网服务"。外网访问防火墙公网 IP 的 80 端口,防火墙把这个包的目的地址改成内网 Web 服务器的 IP,然后转发进去。
🔀 互动演示:NAT 地址转换 (SNAT & DNAT)
网络地址转换(NAT)发生在数据包经过路由前(PREROUTING)或路由后(POSTROUTING)。请尝试发送数据包,观察报文头中的 IP 地址是如何被“偷偷”改写的。
💻
内网 PC
10.0.0.5
🗄️
内网 Web Server
10.0.0.80:80
防火墙 (NAT网关)
内网口 (eth1)
10.0.0.1
10.0.0.1
外网口 (eth0)
203.0.113.10
203.0.113.10
☁️
外部网络
8.8.8.8 / 1.1.1.1
# ========== SNAT 实验:模拟内网主机通过防火墙上网 ==========
# 假设:防火墙内网口 eth1=10.0.0.1,外网口 eth0=192.168.1.10
# 内网网段 10.0.0.0/24 的主机需要通过防火墙访问外网
# 在 WSL 中不要照抄 eth0,先用 ip route show default 确认默认出口网卡
# 先确认内核已开启 IP 转发(如果没开,防火墙没法转发包)
sudo sysctl -w net.ipv4.ip_forward=1
# 在 nat 表的 POSTROUTING 链做 SNAT
# POSTROUTING:路由决策之后、包即将离开本机之前,这时做源地址替换
sudo iptables -t nat -A POSTROUTING \
-s 10.0.0.0/24 \ # 匹配来自内网网段的包
-o eth0 \ # 从外网口出去的包
-j SNAT --to-source 192.168.1.10 # 把源 IP 替换为防火墙外网 IP
# ========== DNAT 实验:把内网 Web 服务器映射到公网 ==========
# 外网用户访问防火墙公网 IP 的 80 端口,转发到内网 Web 服务器 10.0.0.100:80
# PREROUTING:路由决策之前,先改目的地址,然后再决定往哪个口转发
sudo iptables -t nat -A PREROUTING \
-i eth0 \ # 从外网口进来的包
-p tcp --dport 80 \ # 目的端口是 80(HTTP)
-j DNAT --to-destination 10.0.0.100:80 # 改成内网 Web 服务器
# 注意:DNAT 只改了目的地址,还需要 FORWARD 链放行这个转发流量
# 别忘了 FORWARD 链也需要像 INPUT 一样做状态检测
sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A FORWARD -d 10.0.0.100 -p tcp --dport 80 -j ACCEPT
# 验证:从外部访问 http://192.168.1.10:80,应该看到 10.0.0.100 上的网页
# ========== 实验完毕清理 ==========
sudo iptables -t nat -F
sudo iptables -F
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo sysctl -w net.ipv4.ip_forward=0真实输出(2026-05-20,本机 Kali WSL):
# ip route show default
default via 192.168.30.1 dev eth2 proto kernel metric 20
# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth2 -j SNAT --to-source 192.168.30.6
# iptables -t nat -A PREROUTING -i eth2 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.100:80
# iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A FORWARD -d 10.0.0.100 -p tcp --dport 80 -j ACCEPT
# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -i eth2 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.100:80
-A POSTROUTING -s 10.0.0.0/24 -o eth2 -j SNAT --to-source 192.168.30.6
# iptables -S FORWARD
-P FORWARD ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -d 10.0.0.100/32 -p tcp -m tcp --dport 80 -j ACCEPT本机 Kali WSL 的坑
当前默认出口是 eth2,不是文档示例里的 eth0。实验前先用 ip route show default 确认你自己的网卡名,替换命令中的 eth0。另外 Docker 会在 nat 表中维护自己的 DOCKER 链——做 NAT 实验前最好先 sudo iptables -t nat -S > /tmp/nat-backup.txt 保存规则,实验后恢复或重启 Docker,否则可能影响后续靶场容器联网。
实验四:限制连接速率——用 limit 模块防 SSH 暴力破解和 ping 洪水
防火墙不仅是"允许/拒绝"二元选择,还可以限速。如果有人每秒向你发 100 个 ping 包,你可以只接受前 5 个,多的丢弃。
# 先放行已建立连接的回包(必须保留这条,否则正常通信会断)
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 规则 1:限制 ICMP(ping)请求速率——每秒最多 1 个,突发 5 个
# --limit 1/second:长期平均每秒 1 个
# --limit-burst 5:初始令牌桶容量 5 个,允许短时突发
sudo iptables -A INPUT -p icmp --icmp-type echo-request \
-m limit --limit 1/second --limit-burst 5 -j ACCEPT
# 超过限速的 ICMP 包直接丢弃
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
# 规则 2:限制 SSH 新连接速率——每 IP 每分钟最多 3 个新连接
# --state NEW:只限制新建连接,不影响已建立的 SSH 会话
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
-m recent --set # 把新连接的源 IP 记录到"最近列表"
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
-m recent --update --seconds 60 --hitcount 4 -j DROP # 60秒内第4次以上就丢弃
# 验证:快速连续 SSH 连接——前 3 次成功,第 4 次起被拒绝,60 秒后重新计数
# 用另一台机器:for i in {1..10}; do ssh user@目标IP; done
# 实验完毕清理
sudo iptables -F
sudo iptables -P INPUT ACCEPT真实输出(2026-05-20,本机 Kali WSL):
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second --limit-burst 5 -j ACCEPT
# iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
# iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy ACCEPT 5 packets, 414 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8 limit: avg 1/sec burst 5
3 0 0 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8本机 Kali WSL 的坑
用本机 ping 127.0.0.1 或 WSL 虚拟网卡自测 ICMP 限速时,ICMP 包走的是 lo 接口,不经过物理网卡的 INPUT 链,所以计数器不涨、limit 规则看不出效果。课堂截图建议从同网段另一台虚拟机、Windows 主机或单独的 network namespace 发起 ping,不要只在 WSL 里打本机地址。
这些规则在实际运维中对应什么: limit 模块就是最简单的 DoS 防护——限制单 IP 的连接速率,防止暴力破解。企业级防火墙在这个逻辑上加了更多维度:单 IP 并发连接数上限、全局新建连接速率上限、应用层请求频率限制……
四、 防火墙策略设计实战
学会了 iptables 命令,下一步是学会设计策略——哪些流量该放、哪些该拦,规则的优先级怎么排。这不是靠背命令能解决的,而是靠"默认为拒绝"的思维方式。
白名单思维 vs 黑名单思维
黑名单:默认全放行,只封已知的恶意 IP 和端口。每次发现新的攻击,加一条封禁规则。这种做法是无穷无尽的追赶游戏——你永远不知道下一个攻击来自哪个 IP。
白名单:默认全拒绝,只放行业务需要的流量。一个 Web 服务器只需要 80、443 端口对外开放。一个内部数据库只需要允许应用服务器的 IP 访问 3306 端口。其他所有流量——不管是不是恶意的——全丢。所以白名单的安全效果是确定的:没放行的就是不通的。
iptables 实现白名单的核心手法就是 -P INPUT DROP——把默认策略设为拒绝,然后逐条 ACCEPT 业务需要的流量。
DMZ 的完整规则设计
假设你有一个三区拓扑,防火墙有三张网卡:外网口 eth0、DMZ 口 eth1、内网口 eth2。写出完整规则:
# ========== 基础设置 ==========
sudo sysctl -w net.ipv4.ip_forward=1
# 默认策略:FORWARD 链全拒绝(白名单),INPUT 链也全拒绝(保护防火墙本机)
sudo iptables -P FORWARD DROP
sudo iptables -P INPUT DROP
# ========== 状态检测基础规则 ==========
# 所有链都放行已建立连接的回包——这是最优先的,避免影响正常通信
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
# ========== 外网 → DMZ:只开放 80、443 ==========
# 外网用户只能访问 DMZ 里的 Web 服务器
sudo iptables -A FORWARD -i eth0 -o eth1 \
-d 10.0.1.10 -p tcp -m multiport --dports 80,443 -j ACCEPT
# ========== DMZ → 外网:允许 Web 服务器主动访问外网(如系统更新) ==========
sudo iptables -A FORWARD -i eth1 -o eth0 \
-s 10.0.1.10 -p tcp --dport 443 -j ACCEPT
# ========== 内网 → DMZ:允许内网运维 SSH 到 Web 服务器进行管理 ==========
sudo iptables -A FORWARD -i eth2 -o eth1 \
-s 10.0.2.0/24 -d 10.0.1.10 -p tcp --dport 22 -j ACCEPT
# ========== 内网 → 外网:允许内网主机上网(做 SNAT) ==========
sudo iptables -A FORWARD -i eth2 -o eth0 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o eth0 -j MASQUERADE
# ========== DMZ → 内网:禁止!即使 Web 服务器被攻破,也访问不了内网 ==========
# 不需要写规则——因为 FORWARD 默认是 DROP,没明确放行的全丢弃
# ========== 防 DoS 规则 ==========
# 限制外网到 DMZ 的新建连接速率
sudo iptables -A FORWARD -i eth0 -m state --state NEW \
-m limit --limit 100/second --limit-burst 200 -j ACCEPT为什么最后一条放在末尾: 因为前面的 ACCEPT 规则已经匹配了正常的 Web 流量(它们是 ESTABLISHED 或 RELATED 状态,不走 --state NEW 这条规则)。最后这条规则是限制"新建连接速率"——也就是限制新访客的 HTTP 请求、限制攻击者发起新连接的速度。
iptables 进阶:自定义链和 ipset
在实际运维中,你会碰到一个尴尬的情况:需要封禁的 IP 越来越多——单个 IP 还好,一条规则一个。如果黑名单里有 5000 个 IP,你要写 5000 条 iptables 规则。别说管理了,光是遍历规则匹配就是性能灾难。iptables 提供了两个解决方案。
自定义链(Custom Chain): 把同一类规则组织到一个自定义链里,主链一条 -j 跳转就行。规则逻辑清晰,增删方便。
# 创建一个名叫 BLACKLIST 的自定义链
sudo iptables -N BLACKLIST
# 在 BLACKLIST 链里添加被封 IP
sudo iptables -A BLACKLIST -s 192.168.1.100 -j DROP
sudo iptables -A BLACKLIST -s 10.0.0.55 -j DROP
sudo iptables -A BLACKLIST -s 172.16.0.200 -j DROP
# 让 INPUT 链的流量先经过 BLACKLIST 链检查
sudo iptables -I INPUT 1 -j BLACKLIST
# 查看 BLACKLIST 链的规则
sudo iptables -L BLACKLIST -n -v
# 单独清空 BLACKLIST 链而不影响其他规则
sudo iptables -F BLACKLIST真实输出(2026-05-20,本机 Kali WSL):
# iptables -L BLACKLIST -n -v
Chain BLACKLIST (1 references)
pkts bytes target prot opt in out source destination
0 0 DROP all -- * * 192.168.1.100 0.0.0.0/0
0 0 DROP all -- * * 10.0.0.55 0.0.0.0/0
0 0 DROP all -- * * 172.16.0.200 0.0.0.0/0自定义链的好处是:你要临时加一条封禁,不用去 INPUT 链里找插入位置,直接在 BLACKLIST 链尾部追加。你要暂时解除所有封禁,不用改 INPUT 链,-F BLACKLIST 一键清空。
ipset:为大黑名单而生。 当你的黑名单达到数千甚至数十万规模时(比如加载了威胁情报 IP 列表),自定义链也不够用了——iptables 的规则匹配是逐条遍历,10000 条规则匹配一次就要遍历 10000 次。ipset 用哈希表存储 IP 集合,O(1) 时间复杂度——不管列表多大,匹配一个 IP 只用一次哈希运算。
# 安装 ipset
sudo apt install -y ipset
# 创建一个名为 blacklist 的 IP 哈希集合
sudo ipset create blacklist hash:ip
# 批量添加 IP(支持脚本导入威胁情报数据)
sudo ipset add blacklist 192.168.1.100
sudo ipset add blacklist 10.0.0.55
# 甚至可以导入整个 CIDR 网段
sudo ipset add blacklist 58.218.0.0/16
# iptables 里只用一条规则匹配整个 ipset
sudo iptables -I INPUT -m set --match-set blacklist src -j DROP
# 查看 ipset 集合内容和统计
sudo ipset list blacklist
# 保存 ipset 到文件(重启后恢复)
sudo ipset save > /etc/ipset.conf
sudo ipset restore < /etc/ipset.conf本机 Kali WSL 的坑
当前镜像未预装 ipset。如果要继续做大黑名单实验,先执行 sudo apt install -y ipset;这一步属于补装工具,不影响前面的 iptables 基础实验。注意:ipset 创建的集合在重启后会丢失,记得 ipset save > /etc/ipset.conf 持久化。
这就是为什么企业级防火墙能做到"毫秒级匹配百万黑名单"——底层就是哈希表,不是遍历。
攻击者怎么绕过防火墙——以及你怎么防御
你学会了写规则,但攻击者也在学习怎么绕过规则。了解攻击手法不是为了攻击,而是为了写出真正有效的防御策略。
手法一:端口复用。 你的策略"只开放 80 和 443,其他全封"。攻击者在自己的服务器上也开 80 端口做反向代理——你的内网主机主动连接攻击者服务器的 80 端口(这个方向你的防火墙放行了),连接建立后攻击者通过这条已建立的 TCP 连接反向控制你的内网主机。
防御: 除了端口限制,还要限制出站流量的方向——内网主机能访问的 80/443 端口应该仅限于白名单域名/IP,不能是任意地址。NGFW 的应用识别功能可以做到"允许 HTTP 浏览但禁止通过 HTTP 协议传输的非网页内容"。
手法二:DNS 隧道。 你的策略放行 DNS(UDP 53),攻击者把要传的数据编码成 DNS 查询请求发出去——base64encodeddata.attacker.com。你的 DNS 服务器帮你把这条"查询"转发到了攻击者的 DNS 服务器,数据就这样泄露出去了。因为防火墙看到的是正常的 DNS 流量,规则放行。
防御: 限制内网主机只能使用企业自建的受信任 DNS 服务器,在 DNS 服务器上做域名白名单和查询长度检测。正常的 DNS 查询域名段不会超过几十个字符,超长域名很可能是隧道。
手法三:ICMP 隧道。 和 DNS 隧道同理,把数据编码进 ICMP 包的 payload 里。防火墙通常放行 ICMP(至少放行 ping),攻击者就能用 ping 包传数据。
防御: 对外部 ICMP 做严格限制——只允许 echo-request(ping)和 echo-reply(pong),阻止其他 ICMP 类型。如果不需要 ICMP 出站,直接全封。
手法四:分片绕过。 TCP 包可以分片传输。攻击者故意把恶意载荷分散到不同的 TCP 片段里——单独看每一片都不触发规则匹配。早期的包过滤防火墙只检查第一个分片,攻击者把恶意内容放在后续分片里就能绕过。
防御: 现代状态检测防火墙会自动重组分片后再做规则匹配,不存在分片绕过。如果你的 iptables 规则用了 -f(匹配分片包),确保对所有分片都做相同的策略检查。
防火墙日志分析:从日志中发现问题
防火墙不只是一道闸门,还是你的"监控摄像头"。每一条被拒绝的包都是一条线索——有人在对你的网络做什么。
# 在 iptables 规则里加上 LOG 动作——拒绝之前先记录
# 注意:LOG 规则必须放在 DROP 规则之前,因为 DROP 后就到不了 LOG 了
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
-m recent --update --seconds 60 --hitcount 4 -j LOG \
--log-prefix "SSH BRUTE-FORCE: " --log-level 4
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
-m recent --update --seconds 60 --hitcount 4 -j DROP
# 查看防火墙日志
sudo tail -f /var/log/kern.log | grep "SSH BRUTE-FORCE"日志里的可疑模式:
- 同一源 IP 在短时间内访问了大量不同端口 → 端口扫描。应立即封禁该 IP。
- 同一源 IP 在短时间内访问了大量不同内网 IP → 主机发现(Ping Sweep)。攻击者在摸你的内网拓扑。
- 大量 SYN 包来自不同的伪造源 IP → SYN Flood DDoS。需要上游 ISP 协助清洗。
- 某个内网主机突然向外网不可信 IP 发大量连接 → 可能已被植入后门。检查该主机的进程和网络连接。
日志分析工具: 手动 grep 在生产环境不现实。常见的辅助工具:
- fail2ban:自动分析日志 + 自动下发封禁规则(前面已经讲过)。
- psad(Port Scan Attack Detector):专门分析 iptables 日志,自动检测端口扫描并发送告警邮件。
- ELK(Elasticsearch + Logstash + Kibana):把防火墙日志集中收集、索引、可视化——能做出"今天哪个 IP 被封次数最多""本周最活跃的攻击来源国家"之类的图表。这是安全运维工程师的核心技能。
五、 更简单的防火墙管理:ufw 和 fail2ban
你现在会用 iptables 写规则了。但说实话,在生产环境里手工维护几百条 iptables 规则是件痛苦的事——规则顺序搞反一条就出事故,每台机器的规则还不太一样。Linux 生态里有两个工具极大地降低了防火墙的日常运维成本。
ufw:iptables 的"一键操作"前端
ufw(Uncomplicated Firewall)是 Ubuntu 自带的 iptables 前端。它不增加新功能,只是把常用的 iptables 规则翻译成人类更容易读写的命令。
对比一下同样一个操作,iptables 和 ufw 的写法:
# ===== iptables 写法 =====
sudo iptables -A INPUT -s 192.168.1.100 -p tcp --dport 22 -j DROP
# ===== ufw 写法 =====
sudo ufw deny from 192.168.1.100 to any port 22ufw 的核心命令就几条:
# 启用/禁用防火墙(启用后默认拒绝所有入站、放行所有出站)
sudo ufw enable
sudo ufw disable
# 放行或拒绝端口
sudo ufw allow 80/tcp # 允许所有 IP 访问 80 端口
sudo ufw deny 22/tcp # 拒绝所有 IP 访问 22 端口
# 基于源 IP 的规则
sudo ufw allow from 10.0.0.0/24 to any port 3306 # 只允许内网网段访问 MySQL
# 限速规则(和 iptables limit 模块对应)
sudo ufw limit 22/tcp # 限制 SSH 连接速率,防暴力破解
# 查看规则(带编号,方便删除)
sudo ufw status numbered
sudo ufw delete 3 # 删除第 3 条规则
# 查看 ufw 底层实际生成的 iptables 规则
sudo iptables -L -n -vufw 的使用场景: 个人 VPS、开发环境、小型项目——在这些场景里你不需要复杂的 DMZ 策略,只需要"开放 80/443、限制 SSH、封几个恶意 IP"。ufw 五条命令搞定,iptables 可能需要二十条。
ufw 不适合的场景: 需要做 NAT、需要复杂的 FORWARD 链策略、需要按连接状态做精细控制——这些 ufw 表达不了,你还是得回到 iptables。
fail2ban:自动封禁暴力破解 IP
fail2ban 做的事和防火墙不同——它自己不拦包,而是读日志。当它发现某个 IP 在短时间内产生了大量失败登录记录(SSH 密码错误、Nginx 404 扫描、Postfix 暴力破解),就自动调用 iptables 把这个 IP 临时封禁一段时间。
# 安装 fail2ban
sudo apt install -y fail2ban
# 查看默认启用的"监狱"(jail)——SSH 防护默认开启
sudo fail2ban-client status
sudo fail2ban-client status sshd # 看 SSH 监狱的封禁统计
# 自定义一个 jail:保护 Nginx 不受扫描
sudo tee /etc/fail2ban/jail.local <<'EOF'
[nginx-scan]
enabled = true
port = http,https
filter = nginx-404 # 匹配 Nginx 日志中的 404 错误
logpath = /var/log/nginx/access.log
maxretry = 5 # 60 秒内 5 次 404 就封禁
bantime = 3600 # 封禁 1 小时
findtime = 60
EOF
sudo systemctl restart fail2ban工作原理: fail2ban 用正则表达式解析日志文件。当某个 IP 的匹配次数在 findtime 秒内达到 maxretry 次,fail2ban 执行一条 iptables 命令——相当于 iptables -I INPUT -s 攻击者IP -j DROP。封禁时间到了之后自动删除这条规则。
fail2ban 和 iptables 的关系: fail2ban 是"自动化 iptables 规则下发器"。你不需要手动盯着日志封 IP——fail2ban 帮你做。但它只处理"基于频率的攻击"(暴力破解、扫描),不处理协议层面的攻击(SQL 注入、XSS)——那些是 WAF 的事。
ufw + fail2ban 组合实战:保护一台公网 VPS
典型的个人 VPS 最小化防护方案:
# 1. ufw:白名单策略
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw limit 22/tcp # SSH 加限速
sudo ufw enable
# 2. fail2ban:自动封扫描和暴力破解
sudo apt install -y fail2ban
# 默认 sshd jail 已生效
# 再加一个封端口扫描的规则——
# 如果某个 IP 连续访问了 5 个以上不同端口,很可能是扫描器
sudo tee /etc/fail2ban/jail.local <<'EOF'
[portscan]
enabled = true
filter = portscan
logpath = /var/log/kern.log
maxretry = 5
bantime = 7200
findtime = 60
EOF这个组合可以自动挡掉 90% 以上的自动化攻击流量。剩下的 10% 是精心构造的应用层攻击——留给 WAF(第16课)。
六、 中国防火墙(GFW):国家级的包过滤系统
学到这儿,你可能会想到一个问题:我们在国内上网时,有些国外网站打不开——这和我们学的防火墙是一回事吗?
技术上确实有共通之处,但规模、目的和手段完全不同。
GFW 是什么
GFW(Great Firewall,中国国家防火墙)是中国政府在互联网边境部署的一套国家级网络访问控制系统。它不是一个单一的"设备",而是分布在全国各国际出口上的一个复杂的过滤系统,综合使用了多种技术手段。
GFW 用到的技术手段
第一:IP 黑名单。 直接封锁特定 IP 地址的访问——最粗暴、最有效。如果某个服务器的 IP 被列入黑名单,从中国境内发往该 IP 的所有流量在出口路由上就被丢弃。这和 iptables -A OUTPUT -d 被封IP -j DROP 一个道理,只不过执行规模是全国级别的。
第二:DNS 污染。 当你的电脑查询某个被封锁域名的 IP 地址时,GFW 抢在真实 DNS 服务器回复之前,发一个假的 DNS 响应给你——里面写的是一个错误的 IP,或者干脆是 127.0.0.1。你的浏览器拿到错误 IP,自然连不上。这种手段比 IP 封锁更隐蔽,因为被封的不是一个 IP,而是一个域名。
第三:DPI(深度包检测)+ TCP 重置。 这是最精妙的手段。GFW 的 DPI 设备实时分析经过国际出口的所有流量。当它检测到某个 TCP 连接中出现了敏感关键词(比如某个被封锁的域名出现在 TLS 握手的 SNI 字段里),它会伪造一个 TCP RST 包发给你和服务器——你以为是对方断开了连接,其实是 GFW 在中间"劝架"。这个操作非常快,通常在 TCP 握手完成后的几十毫秒内完成。
第四:协议特征识别。 这是第14课讲翻墙工具时提到的——Shadowsocks、V2Ray、Trojan 这些工具的设计目标就是绕过 GFW 的协议识别。反过来,GFW 也在不断升级自己的流量分析能力,用机器学习模型来识别"看起来像正常 HTTPS 但统计特征不太对"的加密流量。
GFW 和企业防火墙的区别
| 维度 | 企业防火墙 | GFW |
|---|---|---|
| 目的 | 保护企业网络免受外部攻击 | 控制境内用户对境外内容的访问 |
| 方向 | 主要防"进来"(保护内网) | 主要防"出去"(限制出境访问) |
| 规模 | 一个企业边界 | 整个国家的国际出口 |
| 手段 | 五元组过滤 + SPI | IP 封锁 + DNS 污染 + DPI 注入 RST |
| 法律依据 | 企业安全策略 | 《网络安全法》《计算机信息网络国际联网管理暂行规定》 |
| 是否透明 | 内部网络管理员可审查 | 外部不可见、不可审查 |
课堂立场
本课提及 GFW 只是为了让你理解"国家级防火墙和企业防火墙在技术上有哪些异同"。作为安全从业者,你需要知道 GFW 用了哪些技术手段——不是因为你要去绕过它,而是因为你要理解网络访问控制的多种实现方式,以及技术在何种尺度上可以影响整个国家的网络架构。
你不需要、也不应该去做任何"测试 GFW"的行为。 用第14课学到的翻墙工具主动探测 GFW 的封锁规则,本身就是违法的网络行为。课堂实验仅仅限于本机模拟环境——iptables 的规则检查、ModSecurity 的攻击拦截——不涉及任何跨境网络连接。
本课复盘
学完这一课,你应该能回答这些问题:
- 防火墙解决的核心问题是什么?不是"加一层保护"这个空话,而是三件具体的事:访问控制(五元组匹配)、状态跟踪(SPI 记住连接)、地址转换(SNAT/DNAT 隐藏内网)。
- iptables 的三表五链是什么?filter 表(INPUT/OUTPUT/FORWARD)做过滤,nat 表(PREROUTING/POSTROUTING)做地址转换。一张图概括:包进→PREROUTING→路由决策→FORWARD→POSTROUTING→出。
- 为什么企业要分 DMZ 区?把对外服务的服务器从内网剥离出来,即使被攻破也不会直接进入内网。DMZ 不能主动访问内网。
- 白名单和黑名单的区别是什么?白名单默认拒绝、按需放行,安全边界确定。黑名单默认放行、逐条封禁,永远追在攻击者后面。
-P INPUT DROP和iptables -F的区别是什么?前者设默认策略为拒绝,后者清空所有规则。两个完全不同的操作。
课后任务
以下任务全部截图提交,每张截图需要能看到你输入的命令和终端输出结果。
- 截图基本规则:用 iptables 封禁一个测试 IP 的 SSH 访问(
-p tcp --dport 22 -j DROP),截iptables -L -n能看到规则,再用被封 IP 尝试 SSH 连接失败的图。 - 截图状态检测:设置
-P INPUT DROP,放行ESTABLISHED,RELATED,截一张你 ping 外网通的图(证明回包被状态检测放行)。 - 截图 NAT 映射:用 DNAT 把本机 8080 端口映射到本机 80 端口(
-j DNAT --to-destination 127.0.0.1:80),截访问 8080 能拿到 80 端口内容的图。 - 截图限速防 ping:用
limit --limit 1/second限制 ping,截一张快速 ping(ping -i 0.1)能看到部分包被丢弃的图。 - 截图完整策略:写出并截图一个包含 INPUT/FORWARD 的完整规则集(至少 6 条规则),要求包含状态检测、端口限制和一条 limit 规则。
实验环境清理
# 清空所有 iptables 规则,恢复默认策略为 ACCEPT
sudo iptables -F
sudo iptables -t nat -F
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
# 关闭 IP 转发
sudo sysctl -w net.ipv4.ip_forward=0