摘要
Forwarded与X-Forwarded-For记录的是转发链声明,不是经过认证的客户端身份。接收方能直接观察到的是当前连接的对端;更早地址只有经过明确的代理授权规则才可采用。- 安全控制应同时保留原始字段顺序、解析规则、信任集合版本、第一处不可信边界和最终消费决定。地址格式正确,不等于它有权触发白名单或授权。
失败不在逗号
把事件归结为“请求头可伪造”没有抓到重点。所有请求头本来就是输入。只要客户端能发 HTTP,它就能写入字段。控制失败发生在另一步:应用把列表里的某个字符串升级成了连接事实。
源站真正掌握的本地观察是 socket peer。这个地址未必是最终用户,它可能是一台负载均衡器;但它来自本机传输栈,而不是来自 HTTP 文本。因此,判断链条能否继续向前追溯,必须从该对端开始。
若对端不在获准声明转发信息的集合中,解析应到此为止。此时选择对端地址,或拒绝不应存在的直连路径,都是可审计的决定。继续读取更左侧的所谓“真实 IP”,则是在让没有授权的说话者自行指定其身份。
标准化字段承诺了什么
RFC 7239 把 Forwarded 定义为可选字段,用于披露代理介入后被改变或丢失的信息。一个元素可分别携带 for、by、host 与 proto。它们描述客户端到代理、代理接口、早先主机信息和早先协议,不能合并为一个身份凭据。
标准还明确指出,Forwarded 不能天然被认为正确:路径上的每个节点,包括最初客户端,都可能误改或恶意修改它。将经过核验的代理列入可信集合,可以为该代理亲自观察并写入的部分提供依据;它并不会倒过来证明代理收到的任意前缀都真实。代理与端点之间若未受保护,链尾同样可能被篡改。
逗号分隔代理元素,分号关联同一元素的参数。unknown 和混淆节点标识也是合法状态,它们表达“不披露”或“无法识别”,而不是等待被强制转换的坏 IP。运行记录必须区分缺失、未知、混淆、格式错误和实际地址。
不要把 XFF 当成 RFC 7239
X-Forwarded-For 广泛使用,却不是 RFC 7239 定义的字段。二者都可能呈现为逗号链,但语法、添加位置、清洗方式和产品默认值并不相同。一份只写“支持 forwarded headers”的架构图,缺少字段名、生成代理、追加规则和消费算法,就还不是安全规范。
AWS ALB 的文档提供了很直观的例子:XFF 可选择 append、preserve 或 remove。append 会保留来请求中的既有内容,再把负载均衡器观察到的地址加到右侧。因此,ALB 的参与只说明右侧新增元素由它写入,并不会给左侧客户端自带内容盖章。
HAProxy 分别提供 XFF 插入行为和 RFC 7239 Forwarded 支持,并对下游读取位置作出具体说明。下游不能从另一种产品或另一条路径借来“取第一个”“取最后一个”的习惯。位置只有与发送端契约相连时才有意义。
可信链从右侧的现实开始
NGINX 用 set_real_ip_from 指定哪些地址有资格提交替换值。启用 real_ip_recursive on 后,它在链中选取最后一个不可信地址;与此同时,$realip_remote_addr 保留原始连接对端。两个值回答不同问题:谁连到了我,以及按本次规则谁被解析为客户端。
Apache mod_remoteip 从右向左处理链,并尖锐提醒:若不限制中间代理,远端用户可以轻易冒充其他地址。Envoy 则根据 use_remote_address 和 xff_num_trusted_hops 从右侧计数,也能按可信 CIDR 判断。少一跳、多一跳或路由分叉都会改变结果。
所以并不存在一个脱离拓扑的“获取真实 IP”操作。可验证的对象只有:当前对端、获准代理集合或跳数、实际字段契约、运行中的遍历算法,以及停止位置。
重复字段与 IPv6 是分歧测试
RFC 9110 允许把适用列表语法的重复字段行按接收顺序合并,逗号作为分隔符。边缘代理、HTTP 库、应用框架和日志组件可能分别暴露原始多行、合并字符串或已解析数组。安全测试必须主动发送重复行,确认所有消费者看见相同顺序。
IPv6 又会放大简单切分的缺陷。地址自身含冒号,端口再引入一个边界,RFC 7239 还涉及引号和方括号。用 split(':') 一类方法很容易让访问控制与日志得出两个不同地址。负向用例至少应覆盖带引号 IPv6、带端口 IPv6、IPv4 加端口、unknown、混淆标识、空白变化和错误分隔符。
规范化只能证明“字符串被怎样解释”,仍不能证明“谁有权提交它”。这两项结果必须分开记录。
host 与 proto 也不能搭便车
代理常用转发字段恢复终止 TLS 前的主机名和协议,用于生成重定向、绝对 URL、安全 Cookie 或来源判断。但客户端写入 proto=https,不等于可信边缘确实接收了 TLS;写入某个 host,也不认证目标来源。
不同参数应有不同消费者和信任规则。某个系统可以信任边缘声明观察到的地址,却从固定路由表获得公开主机名。不能因为一个参数有用,就把整组字段宣布为可信。
PROXY protocol 是另一套账
PROXY protocol 在 HTTP 之前传递源与目的信息。它能够跨 TCP 或 TLS 负载均衡保留地址,却不会因为更靠近传输层就自动更可信。接收端必须在专用或严格控制的监听器上启用它,并只接受授权发送者。否则,任意客户端都能伪造一个前言来指定源地址。
正确记录应保留真实对端、是否预期并接受 PROXY 前言、前言声明的地址,然后再进入 HTTP 字段账本。把 socket peer、PROXY 地址、XFF 和 Forwarded 全部覆盖到一个 client_ip 变量,会丢掉证据保管链。
用失败路径写规范
先从边缘之外直接访问源站。若设计声称此路不存在,连接就应在 HTTP 之前失败。随后从未经授权的对端提交白名单 XFF,确认应用不会采用。
再经合法边缘,在链首加伪造地址,验证清洗或追加规则;插入一台不可信代理,确认遍历在第一处不可信位置停止;减少或增加预期跳数,观察固定跳数策略是否明确回退,而不是悄悄换一个“客户端”。
最后比较边缘、源站、框架、限流器、授权模块和日志的解析结果,并从未授权地址发送 PROXY protocol 前言。配置文件只能说明意图,这些运行测试才说明真正的规则。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
