九零不老心
Published on 2026-10-20 / 2 Visits
0

四层 TCP‑IP vs 七层 XFF 黑白名单有效性完整总结

核心区分: 四层:校验 TCP 报文头部源 IP;七层 XFF:校验 HTTP 应用层请求头文本 伪造风险、适用场景、限制条件完全不同,结合你前面网关日志遇到的多级代理、NAT 出口漂移一并汇总。

1、四层(安全组 / 网络 ACL / 防火墙,基于 TCP 源 IP)

原理

读取 TCP/IP 数据包 IP 头里的源 IP,属于网络层,在 HTTP 解析之前完成过滤,根本不看 HTTP 头部。

伪造可能性

  1. 公网正常 TCP 业务连接:几乎无法伪造 TCP 需要三次握手,伪造源 IP 的 SYN 包,回包会路由到被伪造的 IP,攻击者收不到 SYN+ACK,无法建立完整 TCP 连接,业务请求跑不起来。

注意:DDoS 攻击可以发伪造源 IP 的裸 SYN 包,但只能做攻击,不能完成正常 HTTP 业务交互。

  1. 内网 / 同网段环境:可以 IP 欺骗 内网没有路由回包校验,可构造伪造源 IP 报文;但公网互联网业务几乎遇不到。

致命限制(非常关键,就是你遇到的场景)

只要中间经过 NAT、代理、LB、WAF、API 网关,四层看到的是【上一跳代理 / NAT 出口 IP】,看不到原始客户端 IP。

  1. 如果上一跳出口 IP 是固定 EIP / 专线固定 IP:✅四层黑白名单可用,但是只能管控代理出口,不是原始客户端;

  2. 如果上一跳是共享 NAT 地址池、多节点集群出口(你的日志:220.202.19.150/.152/.160漂移):❌不可用,IP 不断变化,无法精准限制;

  3. 家用宽带 PPPoE 动态 IP / CGNAT 共享 IP:❌四层黑白名单基本没法针对终端用户做限制。

优点 & 缺点

✅ 优点:无法被业务请求伪造;性能极高,请求还没进应用就拦截;抵御部分 DDoS ❌ 缺点:拿不到真实客户端 IP;依赖上一跳出口 IP 必须固定;多级代理场景粒度太粗


2、七层 X‑Forwarded‑For(XFF)黑白名单(API 网关、WAF 七层规则)

原理

读取 HTTP Header 文本,逗号分割 IP 列表,属于应用层。

伪造可能性

非常容易伪造,攻击者客户端直接自定义请求头即可篡改 XFF 内容。

X‑Forwarded‑For: 白名单IP

⚠️ 如果公网流量可以直接打到网关,没有前置可信代理,攻击者伪造 XFF 可以直接绕过 IP 白名单。

什么情况下 XFF 才安全?

必须上游是可信代理(ALB / CLB / WAF),并且代理做清洗:

  1. 丢弃客户端原始传入的 X‑Forwarded‑For 头,不要继承

  2. 代理把自己 TCP 四层收到的真实源 IP 追加到 XFF 列表末尾

只有经过可信代理清洗后的 XFF,里面的 IP 序列才可信;否则 XFF 只是一串可篡改的文本,没有安全意义。

致命限制

  1. XFF 数组长度可变:经过的代理层数不一样,IP 数量不一样(你的日志:2 个 IP / 3 个 IP 两种情况); 👉 禁止写死拦截位置下标! 固定下标,链路一跳发生变化,匹配直接错位失效。 👉 正确做法:永远取 XFF 最左侧第一个 IP 作为原始客户端 IP(前提上游可信代理正确追加)。

  2. 只作用于 HTTP/HTTPS;非 HTTP 协议(TCP、UDP)拿不到 XFF。

优点 & 缺点

✅ 优点:可以拿到原始客户端真实公网 IP;多级代理场景依然可以识别源头 IP;适合业务维度 IP 管控 ❌ 缺点:原始请求可伪造;必须依赖可信代理清洗;只能处理 HTTP 类流量;在应用层处理,性能弱于四层。


3、场景对照表(结合你的业务)

表格

场景

推荐方案

风险说明

上游是固定 EIP 代理,只想限制代理接入

四层黑白名单

公网无法伪造,安全;但管控粒度是代理,不是真实客户端

需要限制真实客户端出口 IP,流量经过多级 LB/WAF/ 网关

七层 XFF(上游必须可信代理清洗 XFF)

禁止公网直连网关;不要写死 XFF 下标

公网用户直接访问网关,没有前置可信代理

❌不能用 XFF 白名单

客户端可伪造 XFF 直接绕过;只能用四层,但是四层只能看到客户端出口 IP

云内共享 NAT 地址池访问网关(你的日志场景)

只能用七层 XFF

四层源 IP 漂移,无法四层做客户端 IP 限制

家用宽带动态 IP/CGNAT 用户接入

只能七层 XFF

家用出口 IP 动态变化,四层黑白名单完全不可行

4、生产环境最佳实践(组合防护)

  1. 网络层(四层):安全组 / ACL 只放行可信上游代理的 IP 段,禁止公网直接访问 API 网关实例。把不可信流量直接挡在应用外面。

  2. 应用层(七层):API 网关开启 XFF 黑白名单,依靠可信代理清洗后的 XFF,取最左侧 IP 做客户端 IP 管控。

两层叠加:四层保证网关不会被原始公网直接触碰,杜绝 XFF 伪造绕过风险;七层实现对真实客户端 IP 业务级访问控制。

5、两个高频踩坑总结

  1. ❌坑:公网流量直打网关,直接开启 XFF 白名单。

后果:攻击者构造伪造 XFF 头绕过白名单。

  1. ❌坑:XFF 拦截位置写死固定数字。

后果:链路代理层数变化(多跳 / 少跳),IP 数组长度改变,匹配错位,放行 / 拦截全部错乱,就是你之前 1、2、3 位置都不对的根源。

  1. ✅正确:可信代理清洗 XFF,取 XFF 数组最左侧第一个 IP作为原始客户端 IP。

极简记忆口诀

四层看包,不怕伪造,但只能看见上一跳;上一跳 IP 一变,规则直接报废。 七层看头,能拿到真实客户端,但是头可篡改;必须可信代理清洗,不能写死数组下标。

什么是可信代理清洗 XFF

清洗 = 扔掉客户端自带、可伪造的原始X‑Forwarded‑For,代理自己根据【四层 TCP 真实源 IP】重新构建一份 XFF 列表,再向后传递。 可信代理 = 这个代理设备你完全掌控(云厂商 CLB/WAF/API 网关、自建 Nginx),攻击者无法绕过它直接打到后端。

❶ 不做清洗(危险!绝大多数人踩坑)

攻击者直接发 HTTP 请求,自己随便写伪造头:

curl -H "X‑Forwarded‑For: 101.126.36.10" https://your-api.com
  • 代理不删除这个头,直接追加自己的 IP往下游转发

  • 到达网关的 XFF 变成:101.126.36.10, 代理IP

  • 后端看到最左边是白名单 IP,直接放行 → 绕过 IP 白名单

问题根源:XFF 只是 HTTP 文本,客户端完全可以自定义;这个伪造内容被原样透传到后端。

❷ 做清洗(安全)

可信代理收到攻击者请求:

  1. 直接丢弃请求里面自带的全部X‑Forwarded‑For头,把攻击者写的伪造内容全部删掉。

  2. 代理读取四层 TCP 连接真实源 IP(这个是 TCP 报文源 IP,公网无法伪造完整连接)。

  3. 用这个真实 TCP 源 IP,新建 / 重写X‑Forwarded‑For,再继续向后转发。

示例流程

攻击者 TCP 源 IP 是223.1.1.1,同时 HTTP 头伪造X‑Forwarded‑For: 101.126.36.10

  1. 可信代理收到 TCP 连接,四层源 IP=223.1.1.1;http 头带伪造 XFF。

  2. 清洗:删掉传入的 XFF 头,丢弃伪造的101.126.36.10。

  3. 代理新建 XFF:X‑Forwarded‑For: 223.1.1.1,传给下一跳。

👉 下游网关拿到的 XFF 全部是代理根据真实 TCP 连接写出来的,不再是客户端可以随便篡改的文本。

为什么 “经过可信代理清洗后的 XFF 就可靠”?

  1. 所有 IP 条目来源,不再来自客户端 HTTP 头;来自 TCP 四层 socket 源 IP。 TCP 四层源 IP 公网环境下,攻击者无法伪造建立完整业务连接。

  2. 攻击者不能绕过可信代理:后端服务器安全组 / ACL 只放通可信代理的 IP 段;公网流量根本无法直连后端。

    如果攻击者可以绕开代理直接访问后端,那清洗就失去意义,攻击者可以直打后端继续伪造 XFF 头。

  3. 每一跳可信代理只会追加自己四层看到的上一跳 IP,不会接收、保留客户端传入的伪造内容。

⚠️ 注意:XFF 本身没有加密签名,不是不可篡改;是 “入口被可信代理封住,所有 XFF 字段全部由可信代理根据四层数据重写”,所以可靠MDN Web Do...。

两种错误理解澄清

❌误区 1:“XFF 头本身有防篡改能力”

XFF 只是普通 HTTP header,没有签名校验。可靠的不是头本身;可靠是流量必须全部经过你可控的代理,代理把客户端伪造内容全部清除,基于四层源 IP 重写。

❌误区 2:“只要是云厂商 LB,就自动帮你清洗 XFF”

不是!要看配置模式

  • 模式 A(危险透传):继承原始 XFF,只追加;客户端伪造内容会保留在列表左侧。

  • 模式 B(安全清洗):丢弃原始传入 XFF,基于 TCP 源 IP 重建 XFF。

火山 ALB、Nginx、Ingress 都要确认开启清洗行为,默认配置很多是透传,不清洗。

结合你日志的现实问题

你的火山 API 网关拿到的 XFF:101.126.36.10, 111.48.137.138, 220.202.19.152

  • 这些 IP 是上游各个可信节点一层层追加出来。

  • 但是链路跳数会变:有时候 2 跳,有时候 3 跳;所以千万不要写死拦截位置下标。 ✅正确做法:网关从右向左遍历 XFF 列表,跳过全部已知可信代理 IP 段,取第一个不属于可信代理网段的 IP,作为真实客户端 IP,而不是写死第 0/1/2 位下标MDN Web Do...。

Nginx 极简示意配置(清洗 XFF)

# 定义哪些是可信代理的IP段(只信任自己的LB)
set_real_ip_from 10.0.0.0/8;

# 从TCP连接获取真实源IP,丢弃上游传来的伪造XFF
real_ip_header X‑Real‑IP;
real_ip_recursive on;

# 向下游转发时,重写XFF,只填入当前四层看到的源IP,不继承客户端传入的XFF
proxy_set_header X‑Forwarded‑For $remote_addr;

最终极简记忆

  1. 没经过可信代理清洗的 XFF = 用户可以随便填写的文本框,完全不能做安全控制。

  2. 清洗 = 扔掉客户端写的 XFF,全部改用 TCP 四层真实源 IP 重新生成 XFF。

  3. 前提约束:公网不能直连后端,全部流量必须经过可信代理,否则清洗无效。

  4. 即使清洗完成,解析 XFF 不要写死数组下标;要配置可信代理 IP 段,从右往左跳过代理 IP 拿到客户端 IP,适配链路跳数变化。