iptables -m length 不能可靠拦截分片绕过攻击,因非首片仅含IP头和分片字段(典型28字节),匹配长度易误判;应使用-m frag在raw表精准控制分片,并禁用nf_defrag_ipv4自动重组。

iptables -m length 本身不能可靠拦截基于分片的绕过攻击,原因在于:分片报文(尤其是非首片)在内核网络栈中尚未重组,其 IP 层载荷极小(通常仅含 IP 头 + 分片偏移字段),长度远低于原始完整包。此时用 --length 匹配的是单个碎片的长度,而非应用层或传输层意义上的“报文长度”,极易误判或漏判。
真正有效的防御必须前置到分片处理环节,而非依赖 length 模块。以下是清晰、可落地的应对逻辑和操作:
明确分片报文的长度特征不可靠
- 首片:含完整 IP 头 + TCP/UDP 头 + 数据,长度可变(如 60–1500 字节)
- 后续片:仅含 IP 头(20 字节)+ 分片字段(8 字节),无四层头,典型长度为 28 字节(IPv4 最小分片)
-
-m length --length 28确实能匹配后续片,但:- 合法大文件传输也会产生大量 28 字节碎片,盲目 DROP 会中断正常业务
- 攻击者可故意构造首片长度 ≈ 28 字节来绕过规则
-
length模块无法区分首片/非首片,也无法识别分片标志位
应该用 -m frag 在 raw 表做精准控制
-m frag 是专为分片设计的匹配模块,可安全识别分片行为,且必须配合 raw 表使用(因其在 conntrack 之前生效):
# 丢弃所有非首片(后续片)——最直接阻断分片绕过 iptables -t raw -A PREROUTING -f -j DROP # 或更精细:只丢弃非首片中携带 TCP 标志位的非法碎片(RFC 791 禁止) iptables -t raw -A PREROUTING -f -m tcp --tcp-flags ALL FIN,SYN,RST,PSH,ACK,URG -j DROP # 限制单 IP 每秒分片数量,防碎片洪水(需 hashlimit) iptables -t raw -A PREROUTING -f -m hashlimit \ --hashlimit-above 5/sec \ --hashlimit-burst 10 \ --hashlimit-mode srcip \ --hashlimit-name frag_per_ip \ -j DROP
必须禁用内核自动重组(关键前提)
默认情况下,nf_defrag_ipv4 模块会在 PREROUTING 早期自动重组分片,导致 raw 表规则失效。需显式卸载该模块:
# 查看是否加载 lsmod | grep nf_defrag_ipv4 # 临时卸载(重启失效) sudo modprobe -r nf_defrag_ipv4 # 永久禁用(写入 blacklist) echo "blacklist nf_defrag_ipv4" | sudo tee /etc/modprobe.d/blacklist-frag.conf sudo update-initramfs -u # Debian/Ubuntu
⚠️ 注意:禁用后,所有上层模块(如 conntrack、state)将无法处理未重组的分片,因此
raw表过滤必须严格——这也是为什么length不适合此处。
filter 表只基于连接状态放行,不查长度
经 raw 表清洗后,filter 表应完全信任 conntrack 状态:
# 允许已建立和相关连接(RELATED 已包含合法重组后的后续片) iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # NEW 连接只检查首片(此时有完整四层头,可放心用 --dport/--syn) iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j ACCEPT # 默认拒绝 iptables -A INPUT -j DROP
不复杂但容易忽略。


















