前言
WAF 部署在防火墙后、通过 DNAT 端口映射对外发布,是中小企业最常见的架构。但不少运维上线后都会踩同一个坑:WAF 日志里的源IP清一色是防火墙内网地址,IP 黑名单、CC 防护、攻击溯源全部失效,防护能力直接打对折。
很多人第一时间怀疑是 WAF 本身的取IP逻辑有问题,反复调试却找不到根源。其实这和 WAF 无关,本质是防火墙在做目的地址转换时,同步执行了源地址转换(SNAT),把客户端真实IP给"抹掉"了------这是 NAT 网络架构的共性问题,所有品牌设备都会遇到。
这篇文章从原理到实操一次讲透:整理了关闭SNAT、XFF 透传、Proxy Protocol 三种主流方案,附带 iptables、华为、H3C 等设备的命令行与图形界面配置步骤,对应雷池 WAF 的参数设置与 Nginx 侧配合方法,同时标注了所有新手高频踩坑点,最后给出完整的验证方法与排错思路,照着配就能让 WAF 拿到真实客户端IP,把防护能力拉满。
群里一位朋友贴了张雷池的截图:"WAF部署在防火墙下面,怎么获取到访问的源IP,现在进来的都显示出口的地址。"另一个群友回得很干脆:如果你WAF是防火墙DNAT端口映射出去的,需要关闭源地址转换,不然包直接带的是防火墙内网地址。
这个场景太常见了------WAF日志里全是 10.x.x.x 或 192.168.x.x,防CC、IP黑名单形同虚设。下面从原理到各厂商的实际配置(含图形界面与命令行),一次讲清楚。

一、为什么WAF只看到防火墙的IP?
典型链路:访客 → 公网 → 防火墙(DNAT映射) → WAF → 源站
防火墙在做DNAT端口映射时,如果同时执行了SNAT(源地址转换),数据包的源IP会被改写成防火墙自己的内网地址。WAF从网络连接里读到的"对端IP"就是防火墙,而不是访客。
雷池官方文档对此的描述很直接:此时与雷池直接建立连接的是最后一跳设备,雷池读到的IP是这个节点的地址。要让WAF拿到真实IP,业内通用的说法叫 "IP透传"。根据防火墙能力和网络架构,有三种方案。

二、方案一:关闭SNAT(网络层透传)
最简单直接。在防火墙的DNAT端口映射规则中去掉SNAT配置,让数据包带着访客的真实源IP直接到达WAF。
以 iptables 为例 ,很多时候运维并没有专门给DNAT加SNAT,而是全局出口的MASQUERADE规则误伤了内网回流的DNAT流量 。建议在 POSTROUTING 链最前面插入一条排除规则:
# 目的地址是内网WAF/服务器网段的流量,直接放行,不做SNAT
iptables -t nat -I POSTROUTING -d 192.168.1.0/24 -j ACCEPT
# 查看规则是否生效
iptables -t nat -L POSTROUTING -n -v --line-numbers
💡 注意必须使用
-I(插入到链首)而非-A(追加到链尾)。如果用-A,规则会排在全局MASQUERADE规则之后,流量先匹配到SNAT就不会走到这条排除规则,最终配置等于无效。
图形化界面怎么配 :在华为、H3C或深信服的Web界面中,找到 策略 -> NAT策略 -> 源NAT(SNAT) ,新建或修改规则时,将"目的地址"排除掉你的WAF或内网服务器网段,动作选择"不转换"或"不执行NAT"。
注意:关闭SNAT后,回程路由需要正确指向WAF。如果WAF和源站不在同一广播域,可能需要配合策略路由或确保WAF的默认网关指向防火墙内网口。
三、方案二:X-Forwarded-For 透传(应用层,最通用)
不关SNAT,让防火墙在HTTP头里"夹带"真实IP。这是绝大多数企业的首选。
3.1 防火墙侧:开启XFF插入
⚠️ 避坑前提 :很多防火墙的XFF插入功能只在七层的"HTTP虚拟服务器/负载均衡"类型下生效 。如果你配置的是普通的四层端口映射(如 nat server),是找不到XFF选项的,必须将发布方式改为七层HTTP反向代理。
华为防火墙(命令行):
system-view
slb
virtual-server <vs-name> type http
http x-forward enable
华三(H3C)防火墙(命令行):
system-view
virtual-server <vs-name> type http
insert-xff enable
图形化界面怎么配 :通常在 服务器负载均衡(SLB) -> 虚拟服务器 中,协议选择HTTP,然后在高级选项中勾选"插入X-Forwarded-For"或"开启XFF"。
3.2 雷池WAF侧:选择XFF获取方式
进入 防护应用 → 高级配置 → 源 IP 获取方式,根据链路层数选择:
- 取 X-Forwarded-For 中上一级代理的地址:适用于只有一层防火墙(访客→防火墙→WAF)。
- 取 X-Forwarded-For 中上上一级代理的地址:适用于两层代理(访客→CDN→防火墙→WAF)。
💡 层级到底怎么看?
XFF的标准格式是
真实IP, 第一层代理IP, 第二层代理IP,从左到右是流量经过的顺序。雷池的"上一级"对应的是XFF最右侧(也就是紧挨着雷池的最后一跳设备)追加的IP,"上上一级"则是倒数第二个,以此类推。千万别搞反了。
⚠️ 伪造风险提示:XFF是应用层头,客户端可以主动伪造。使用XFF透传时,务必确保WAF只信任来自防火墙/可信代理的XFF头。雷池可以在源IP获取配置中配合"可信代理网段"使用,避免黑客自行构造XFF头绕过IP封禁。
3.3 源站Nginx的配合
如果WAF后面还有Nginx,需要启用 realip 模块解析XFF:
set_real_ip_from 192.168.1.0/24; # WAF或防火墙的IP/网段
real_ip_header X-Forwarded-For;
real_ip_recursive on;
四、方案三:Proxy Protocol 透传(传输层,防伪造)
XFF走HTTP头可以被伪造,Proxy Protocol在TCP连接建立时就把真实源IP写进协议头,无法在应用层伪造,适合对IP可信度要求极高的场景。
防火墙侧(以H3C为例):
system-view
virtual-server <vs-name> type tcp
proxy-protocol enable v1
💡 版本选型:v1为可读文本格式,兼容性更好,调试方便;v2为二进制格式,解析性能更高。通用场景优先选择v1,可最大程度避免后端服务兼容问题。
雷池WAF侧 :在 防护应用 → 高级配置 → 源 IP 获取方式 中,选择 "从 PROXY Protocol 中获取"。
Nginx接收方配合 :
如果链路某一段使用Nginx接收Proxy Protocol,必须在 listen 指令上显式声明,否则会报错:
server {
listen 80 proxy_protocol;
set_real_ip_from 192.168.1.0/24;
real_ip_header proxy_protocol;
}
五、配完怎么验证?
不要只看WAF界面"感觉对了"。打开雷池的 防护日志,看请求报文里的源IP字段是否与访客真实公网IP一致。
更严谨的验证方法是用 curl 主动伪造XFF头测试:
# 自行构造XFF头,访问后看WAF日志取的是哪个IP
curl -H "X-Forwarded-For: 1.1.1.1" http://你的站点域名
如果WAF正确配置了可信代理,日志里不会 显示 1.1.1.1,而是你的真实出口IP。如果显示了,说明你的WAF信任了客户端伪造的头,存在被绕过的风险!
排查顺序参考:先确认前置设备有没有把IP传过来 → 再核对WAF的XFF层级是否选反 → 最后检查链路中是否有其他中间设备篡改了请求头。
六、一句话选型
- 能关SNAT就关:网络层直达,零协议开销,但要注意回程路由和全局SNAT误伤。
- 不能关SNAT、要通用:上XFF,防火墙开HTTP虚拟服务器并插入 + WAF取对应层级。
- 要防伪造、链路可控:上Proxy Protocol,但必须确保两端都支持、版本一致。
真实IP取不准,WAF的防护能力等于打折。配完之后花两分钟去日志里验证一眼,比事后排查攻击为什么漏拦划算得多。