
先纠正一个默认假设:转发不等于透传
上个月有个做家居流量站的团队找过来,说跳转插件上线后,后台统计里访客地域分布突然变得特别集中,原本分散在多个省份的访问,七成以上都落到了同一个城市的网段。他们第一反应是投放出问题了,账户查了、关键词查了、落地页也翻了个遍,愣是没找到原因。最后把跳转链路整个画出来才看明白,中间加了两级代理转发,目标端记录的来源IP其实是最后一跳代理的出口地址,真实访客的来源在第一级就被覆盖掉了。
这事儿在跳转插件场景里挺常见的,就是把"代理转发"当成了"原样传递"。转发这个动作只保证请求能到下一跳,来源地址以什么形式呈现给目标,得看每一层代理怎么处理转发头、怎么改写连接信息、目标端又信任哪一段。链路一长,来源识别的口径就会一层层漂移。
所以这篇不聊怎么"藏"来源,聊一个更实际的问题:跳转链路里存在多级代理的时候,你怎么判断目标端看到的来源IP是哪一段,偏差出在哪一层,配置上按什么顺序核对。这属于流量管理和数据口径对齐的范畴,跟对抗没什么关系。
来源IP在哪几层会被改写:链路层级拆解
一个典型的跳转插件链路,从访客点击到目标页响应,中间可能经过这些环节:访客终端、跳转插件的接入层、一级代理、二级代理(或多级转发)、目标站的CDN或负载均衡、目标站源站。来源IP的"真身"只在第一跳的连接里是确定的,往后每一层都可能引入新的地址信息。
连接层地址与转发头地址是两套东西
先把两个概念分开。连接层地址,说的是当前这一跳 TCP 连接的对端地址,目标端在 socket 层面直接就能拿到。转发头地址呢,是 HTTP 头里由上游写进去的来源信息,常见的有 X-Forwarded-For、X-Real-IP、Forwarded 这些。两套东西经常对不上,目标端到底取哪个,看它自己的配置。
- 目标端只取连接层地址的话,多级代理之后,它看到的就是最后一跳代理的出口IP。
- 取 X-Forwarded-For 第一段的话,看到的是最初发起请求的地址,但有个前提——这条链路上每一层都得正确追加,不能覆盖。
- 要是取 X-Forwarded-For 最后一段,那看到的又变成最近一跳代理写入的值了。
麻烦在于,不同代理软件、不同负载均衡产品对这几个头的默认行为都不一样。有的默认追加,有的默认覆盖,还有的遇到已有值干脆不写。链路里只要有一层行为跟你预期不符,来源识别就偏了。
多级转发最容易出问题的三个位置
按我处理过的案例归纳,偏差高发的位置集中在三处。第一处是跳转插件接入层到一级代理之间,接入层如果做了地址转换却没同步写转发头,一级代理就失去了原始来源。第二处是一级到二级代理之间,二级代理要是配了"信任所有上游"、把连接层地址直接当来源,前面写的转发头就白写了。第三处是目标站前面的 CDN 或负载均衡,它只信任自己网段内的转发头,跨网段传来的值会被丢弃或者替换掉。
这三处有个共同点:每一层单独看配置都没毛病,串起来才出问题。所以排查来源识别偏差,不能只盯单点配置,得按链路顺序逐层核对"这一层收到的来源是什么、写出去的来源是什么"。
判断偏差出在哪一层:可执行的核对顺序
与其猜,不如按顺序做几件事。下面这个顺序是我在实际排查里常用的,从成本最低的开始。
第一步:在每一跳打来源快照
在跳转插件的接入层、每一级代理的入口和出口、目标站的接入层,分别记录一次请求到达时的连接层地址和转发头内容。不用全量,抽一小段流量就够。关键是同一批请求要在各层能对上,所以带上一个请求标识,比如在查询参数里加一个随机串,各层日志都记这个串。
这一步的产出是一张对照表:同一个请求标识,在各层看到的连接地址和转发头分别是什么。偏差出现在哪一段,表一拉就清楚了。限制是这需要各层都能加日志,如果某一级代理是托管服务、拿不到日志,就只能用它暴露的调试头或者回源日志来间接判断。
第二步:确认目标端取的是哪一段
拿到对照表之后,还要确认目标端实际用的是哪一段。方法是对比目标端统计里的来源IP和各层快照。如果目标端记录的值等于最后一跳代理的连接地址,说明它取的是连接层;如果等于第一跳的地址,说明它取的是转发头第一段。这一步不需要改任何配置,纯观察。
验证时要注意一点:目标端的统计可能有采样或聚合,不要拿单条记录去对,拿一个时间窗内的分布去对更稳。
第三步:按偏差方向决定改哪一层
偏差方向无非两种。一种是目标端看到的地址比真实来源"更靠后",说明中间有层覆盖了转发头,要改的是那一层的追加策略。另一种是目标端看到的地址"更靠前"但混入了内网地址或不可信值,说明目标端信任了不该信任的上游,要改的是目标端的信任网段配置。 这里有个取舍:改代理层会影响所有经过它的流量,改目标端只影响这一个目标。如果链路是多目标共用的,优先改目标端的信任配置,影响面小。如果目标端不受你控制,那就只能从代理层入手,并且要接受"改完需要重新对齐一次口径"的成本。
配置层面容易踩的四个坑
核对清楚之后,配置上还有几个反复出现的坑,值得单独列出来。
不同代理产品的默认行为差异很大。有的默认在 X-Forwarded-For 末尾追加,有的默认用当前对端地址覆盖整个头。多级串联时,如果一级追加、二级覆盖,最终只剩二级看到的值。配置时要显式声明行为,不要依赖默认值。验证方法是发一个带已知转发头的测试请求,看各层输出。
信任网段配得过宽或过窄
目标端通常会配置"信任哪些上游写入的转发头"。配得过宽,任何上游都能伪造来源;配得过窄,合法的代理写入被丢弃,来源退化成连接层地址。多级代理场景下,信任网段要覆盖到实际会写入转发头的那几层,而不是只配直连的那一层。 代理层和目标站如果在同一内网,转发头里可能混入 10.x、172.16.x、192.168.x 这类地址。目标端如果取第一段,拿到的可能就是内网地址,统计上表现为"来源不明"或归到默认地域。处理方式是在写入转发头时过滤私有网段,或者目标端取值时跳过私有网段。两种方式选一种,别两边都不做。
健康检查流量污染来源统计
代理层和目标端之间的健康检查、探活请求,也会带来源地址。这些请求如果进了统计,会拉偏来源分布。配置上要把探活路径排除在来源统计之外,或者给探活请求打独立标识。这一点在多级代理下更容易被忽略,因为每一级都可能有自己的探活。
实战复盘:两级代理后地域分布失真的排查过程
回到开头那个家居流量站团队。背景是这样:他们做家居品类的内容聚合页,日均点击量在一千二三上下,跳转插件部署在两台中等规格的云服务器上,前面挂了一级反向代理做统一入口,后面又接了一级转发做目标分流,目标站是合作方的落地页,来源统计由合作方提供。
踩的坑是:合作方反馈来源地域高度集中,和他们的投放地域设置对不上,怀疑是流量质量问题。团队先查了投放,又查了落地页内容,折腾了几天没结论。后来按链路快照的办法一拉,发现一级代理到二级代理这一段,二级代理的配置是覆盖式写入转发头,把一级写入的原始来源冲掉了。合作方取的又是转发头第一段,于是拿到的是二级代理的出口地址。
调整过程分两步。第一步改二级代理的写入策略,从覆盖改成追加,并在写入时过滤私有网段。第二步和合作方对齐取值口径,确认他们取第一段,并且信任网段覆盖到二级代理的出口段。改完之后没有立刻看统计,而是先用带请求标识的抽样流量对了一遍各层快照,确认同一批请求在各层能对上,才放开观察。
最终状态是:来源地域分布恢复成和投放设置大致吻合的形态,集中度从七成多降到两成左右。中间还有个插曲,改完第一周统计里出现了一小段内网地址,查下来是探活请求没排除,补了排除规则之后消失。整个过程没有什么高深技术,就是把链路画清楚、把每层的输入输出对上。
实施要点与下一步
如果你现在的跳转链路里有多级代理,并且来源统计看着不对劲,可以按这个顺序推进。先画链路图,标出每一级代理的软件或产品类型、写入策略、信任网段配置。然后抽一批带标识的请求,在各层打快照,做对照表。接着确认目标端取哪一段,按偏差方向决定改代理层还是改目标端。改完不要直接看业务统计,先用抽样请求验证各层对上,再放开观察。最后把探活流量排除掉,避免统计被污染。
需要提醒的是,来源识别偏差不一定是配置错误,也可能是链路设计和统计口径本来就不匹配。多级代理下,"真实来源"这个概念本身就需要先定义清楚:你是要最初发起请求的地址,还是要最近一跳可路由的地址。这两个口径在不同场景下都合理,但混用就会出问题。先把口径定下来,再谈配置怎么改,比一上来就调参数有效得多。
- 检查项一:链路每一级是否显式声明了转发头写入行为,而不是依赖默认值。
- 检查项二: 目标端信任网段是否覆盖实际写入转发头的所有层级。
- 检查项三: 转发头写入时是否过滤私有网段,目标端取值时是否跳过私有网段,两者至少做一项。
- 检查项四: 探活和健康检查流量是否已排除在来源统计之外。
- 检查项五: 来源口径(最初来源还是最近一跳)是否已书面确认并在各层一致执行。
这五项里,前两项决定偏差会不会发生,后三项决定偏差发生之后你能不能快速看出来。多级代理本身不是问题,问题是链路长了之后没人对过口径。把对照表做一次,后面每次加代理层或改配置,都按同样的方法复核一遍,来源识别这块基本就不会再出意外。