状态检测防火墙原理

讲完了包过滤,咱们得聊聊真正的「智能」防火墙了。状态检测,说白了就是防火墙能记住你刚才干了什么。

我记得刚入行那会儿,老工程师跟我说:「防火墙不是傻傻地看每个包,它得会记事儿。」当时不太理解,直到自己配了一回包过滤规则,被各种回程流量折腾得欲哭无泪……嗯,从那以后我才真正明白状态检测有多重要。

状态表与连接跟踪

状态检测的核心,就是一张表——状态表(也叫连接跟踪表)。

这张表长什么样?我直接给你看个简化版:

源IP 源端口 目的IP 目的端口 协议 状态 超时
192.168.1.10 34567 8.8.8.8 53 UDP ESTABLISHED 30s
10.0.0.5 44321 203.0.113.1 80 TCP ESTABLISHED 3600s
172.16.0.2 12345 198.51.100.7 22 TCP NEW 120s

每次有数据包经过,防火墙先查这张表。如果表里有匹配的条目,直接放行,不用再查规则库。这就是状态检测比包过滤快的原因——查表比查规则快得多。

连接跟踪的过程,我习惯分成三步:

  1. 首包创建:第一个SYN包到达,防火墙在状态表里新建一条记录,标记为NEW。
  2. 握手确认:三次握手完成后,状态更新为ESTABLISHED。
  3. 超时清理:连接空闲超过阈值,条目被删除。

关键点:状态表不是无限大的。我见过有人把超时时间设成24小时,结果防火墙内存爆了。生产环境里,TCP默认超时一般是3600秒,UDP更短,30-60秒。

状态检测的优势

说白了,状态检测解决了包过滤的两个大坑:

  • 回程流量不用单独开规则:包过滤你得手动开「允许外部返回流量」,状态检测自动识别。
  • 性能更好:查表是O(1)的哈希查找,查规则是O(n)的线性匹配。
  • 安全性更高:能识别伪造的返回包——如果状态表里没有对应的出站记录,进来的包直接丢弃。

我在项目里遇到过一件事:客户用包过滤,为了能让用户上网,开了「允许所有来自外部的ESTABLISHED包」。结果呢?攻击者伪造ESTABLISHED标志位,直接穿透了防火墙。换成状态检测后,伪造包因为没有对应的状态表条目,全部被拦下。

个人建议:只要条件允许,优先用状态检测。包过滤只适合极简单的场景,比如只允许某个IP访问某个端口,不需要考虑回程流量。

常见状态:NEW / ESTABLISHED / RELATED / INVALID

这四个状态,是状态检测防火墙的基石。我一个个讲。

NEW

表示这是一个新连接的第一个包。对于TCP,就是SYN包。对于UDP,就是第一个数据包。

规则里一般这样写:

iptables -A FORWARD -m state --state NEW -p tcp --dport 80 -j ACCEPT

意思是:允许内网用户发起新的HTTP连接。

ESTABLISHED

表示这个连接已经完成了握手(TCP)或者已经双向通信过(UDP)。

这是最常用的状态。几乎所有状态检测防火墙都会有一条默认规则:

iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

这条规则放行所有已建立的连接和相关的辅助连接。

RELATED

这个状态有点意思。它表示当前包属于一个已存在连接的「子连接」或「辅助连接」。

最常见的例子是FTP的主动模式和被动模式。FTP控制连接用21端口,数据连接用20端口或者随机端口。没有RELATED状态,你得手动开一堆端口。有了它,防火墙能自动识别数据连接属于哪个控制连接。

我记得有一次帮客户排查FTP问题,他们开了21端口,但数据传输就是失败。一看规则,没写RELATED状态。加上之后,问题立刻解决。

INVALID

这个状态表示包无法被识别,或者状态表里找不到匹配的条目,或者包本身有问题(比如TCP标志位组合非法)。

对于INVALID的包,标准做法是直接丢弃:

iptables -A FORWARD -m state --state INVALID -j DROP

警告:千万不要放行INVALID状态的包。我曾经见过有人为了省事,把INVALID也ACCEPT了,结果被扫描工具利用,绕过了防火墙的访问控制。INVALID包就是垃圾,直接扔掉。

状态转换流程

为了让你更直观地理解,我画了一张状态转换图:

状态检测防火墙 - 状态转换图 NEW ESTABLISHED RELATED INVALID 三次握手完成 非法标志位/超时 FTP数据连接等 RST/超时 说明 NEW:首包到达 ESTABLISHED:连接已建立 RELATED:关联子连接 INVALID:非法/无法识别

从图上你能看到,正常的连接路径是 NEW → ESTABLISHED。如果出现非法包或者超时,就会跳到 INVALID。RELATED 是从 ESTABLISHED 分支出来的,用于处理像 FTP 数据连接这样的场景。

实际配置示例

最后,给你一个完整的 iptables 状态检测配置示例:

# 清空现有规则
iptables -F
iptables -X

# 默认策略:丢弃所有流量
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# 允许回环接口
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 允许已建立和相关的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许内网发起新连接(HTTP/HTTPS/DNS)
iptables -A FORWARD -i eth1 -m state --state NEW -p tcp --dport 80 -j ACCEPT
iptables -A FORWARD -i eth1 -m state --state NEW -p tcp --dport 443 -j ACCEPT
iptables -A FORWARD -i eth1 -m state --state NEW -p udp --dport 53 -j ACCEPT

# 丢弃无效包
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state INVALID -j DROP

避坑指南:我曾经在配置时忘了加 ESTABLISHED,RELATED 的放行规则,结果内网能发请求,但回不来任何数据。排查了半天才发现是回程流量被默认策略丢弃了。记住:ESTABLISHED 规则一定要放在最前面。