X-Forwarded-For、Via 等 HTTP 代理头由代理服务器用于向上游服务器传递有关原始客户端、请求路径以及其他上下文数据的信息,而这些信息本来会因代理的存在而被掩盖。
当一个 HTTP 请求经过一个或多个代理服务器时,紧邻的上游服务器通常看到的是最后一个代理的 IP 地址,而不是原始客户端的地址。代理头通过添加或修改特定的 HTTP 头来解决这一问题,使原始客户端的 IP、协议、主机以及代理的先后顺序能够传达给最终的目标服务器。
X-Forwarded-For
X-Forwarded-For(XFF)头是一个事实标准的头字段,用于标识通过 HTTP 代理或负载均衡器连接到 Web 服务器的客户端的源 IP 地址。
用途
它的主要用途是让 Web 服务器能够获取原始客户端的 IP 地址,用于日志记录、数据分析、安全以及特定于应用的逻辑(例如基于 IP 的访问控制、地理定位)。如果没有 XFF,所有请求看起来都来自代理服务器的 IP 地址。
格式与示例
XFF 头可以包含以逗号分隔的 IP 地址列表。当请求经过多个代理时,每个代理都会把连接到自己的那个客户端的 IP 地址追加到 XFF 头中。
X-Forwarded-For: <client>, <proxy1>, <proxy2>
示例 1:单个代理
客户端(192.0.2.1)连接到代理(198.51.100.1),代理再连接到源站服务器。
代理添加:
X-Forwarded-For: 192.0.2.1
源站服务器看到请求来自 198.51.100.1,并带有 X-Forwarded-For: 192.0.2.1。
示例 2:多个代理
客户端(192.0.2.1)连接到代理 A(198.51.100.1),代理 A 连接到代理 B(203.0.113.1),代理 B 再连接到源站服务器。
1. 客户端到代理 A:代理 A 添加 X-Forwarded-For: 192.0.2.1。
2. 代理 A 到代理 B:代理 B 收到 X-Forwarded-For: 192.0.2.1,并向其追加 198.51.100.1。
该头变为:X-Forwarded-For: 192.0.2.1, 198.51.100.1。
3. 代理 B 到源站服务器:源站服务器收到 X-Forwarded-For: 192.0.2.1, 198.51.100.1。
在代理链中,最左侧的 IP 地址通常是原始客户端。最右侧的 IP 地址是紧邻的上游代理(即连接到当前代理的那个客户端)的 IP。
X-Forwarded-For 的安全注意事项
X-Forwarded-For 头很容易被恶意客户端伪造。客户端可以发送带有伪造 X-Forwarded-For 头的请求。
GET / HTTP/1.1
Host: example.com
X-Forwarded-For: 10.0.0.1, 1.1.1.1
如果代理不加判断地在其后追加,源站服务器收到的头可能是 X-Forwarded-For: 10.0.0.1, 1.1.1.1, <proxy_ip>。
因此,下游应用不应直接信任 X-Forwarded-For 头的全部内容。通行的做法是:先剔除属于已知可信代理的条目,再把列表中最右侧的不可信 IP 地址视为真实的客户端 IP。许多 Web 服务器和应用框架都提供了指定可信代理列表的机制。
Via
Via 头是一个标准 HTTP 头,用于指明请求(或响应)所经过的中间代理和网关。
用途
Via 头有以下几个作用:
* 可追溯性:提供代理链的追踪信息,便于排查网络路径问题。
* 环路检测:有助于发现代理链中的请求环路。
* 协议兼容性:标明每个中间代理使用的协议版本,这在协议转换时可能很重要。
格式与示例
每个代理都会向该头添加自己的 Via 条目。每个条目的格式为 protocol-name/protocol-version host:port (comment)。comment 字段可选,可包含任意信息。
Via: <protocol-name>/<protocol-version> <host>:<port> (comment)
示例:
客户端发送的请求经过代理 A(hostname 为 proxy-a.example.com,端口 8080)和代理 B(hostname 为 proxy-b.example.com,端口 80)。
- 客户端到代理 A:代理 A 添加
Via: HTTP/1.1 proxy-a.example.com:8080。 - 代理 A 到代理 B:代理 B 收到
Via: HTTP/1.1 proxy-a.example.com:8080,并把自己的条目前置。
该头变为:Via: 1.1 proxy-b.example.com, 1.1 proxy-a.example.com:8080。
(注意:当协议是 HTTP 时,HTTP/通常会省略;80/443 端口也可能被省略。) - 代理 B 到源站服务器:源站服务器收到完整的
Via头。
隐私与运维注意事项
Via 头会暴露内部网络拓扑和主机名,在某些部署中这可能构成安全或隐私风险。企业可以选择在对外的代理上剥离或修改该头,以避免泄露内部网络信息。
Forwarded
Forwarded 头是 RFC 7239 定义的标准化头字段,旨在取代事实标准的 X-Forwarded-For、X-Forwarded-Host 和 X-Forwarded-Proto。
用途
它以更结构化、更易扩展的方式,把原始客户端、代理自身以及原始请求上下文(主机、协议)的信息传递给上游服务器。
格式与示例
Forwarded 头可以包含一组或多组以逗号分隔的参数,分别代表链路中的每个代理。每组参数使用键值对。常见参数包括:
* for:原始客户端的 IP 地址(或混淆后的标识符)。
* by:转发该请求的代理的 IP 地址(或混淆后的标识符)。
* host:客户端请求的原始 Host 头。
* proto:客户端使用的原始协议(例如 http 或 https)。
Forwarded: for=<client_ip>; proto=<protocol>; host=<original_host>
Forwarded: for=<client_ip>, for=<proxy_ip>; proto=<protocol>
示例 1:单个代理
客户端(192.0.2.1)通过 HTTPS 连接到代理(198.51.100.1),请求 example.com。
代理添加:
Forwarded: for=192.0.2.1; proto=https; host=example.com
示例 2:多个代理
客户端(192.0.2.1)-> 代理 A(198.51.100.1)-> 代理 B(203.0.113.1)-> 源站服务器。
1. 客户端到代理 A:代理 A 添加 Forwarded: for=192.0.2.1; proto=https; host=example.com。
2. 代理 A 到代理 B:代理 B 收到该头,并追加自己的条目,其中包含用于标识自身的 by。
该头变为:
Forwarded: for=192.0.2.1; proto=https; host=example.com, for=198.51.100.1; by=203.0.113.1
(注意:除非某个代理进行了协议或主机重写,否则 host 和 proto 参数通常只出现在对应原始客户端的第一个条目中。)
对比:X-Forwarded-For 与 Forwarded
| 特性 | X-Forwarded-For |
Forwarded |
|---|---|---|
| 标准状态 | 事实标准(非标准的 X- 头) |
RFC 7239 标准 |
| 信息量 | 仅客户端 IP 地址 | 客户端 IP、代理 IP(by)、原始主机、原始协议(proto) |
| 结构 | 以逗号分隔的 IP 地址列表 | 以逗号分隔的结构化键值参数组列表 |
| 可扩展性 | 仅限于 IP 地址 | 可通过附加参数高度扩展 |
| 采用度 | 现有软件与基础设施广泛支持 | 采用率在上升,但目前不如 XFF 普及 |
| 安全性 | 易被伪造,需谨慎解析 | 同样可能被伪造,但结构化解析有助于提升健壮性 |
其他代理头
X-Forwarded-Host
这个事实标准的头字段标识客户端在 Host HTTP 请求头中请求的原始 Host。当代理或负载均衡器在把请求转发给上游服务器之前修改了 Host 头(例如用于内部路由),而应用又需要知道客户端最初请求的主机以完成生成绝对 URL、处理虚拟主机等任务时,它就派上用场。
示例:
客户端请求 example.com。代理转发到内部主机 app-server-1。
Host: app-server-1
X-Forwarded-Host: example.com
X-Forwarded-Proto
这个事实标准的头字段标识客户端连接到代理或负载均衡器时使用的协议(HTTP 或 HTTPS)。当代理执行 SSL/TLS 终止时(即客户端通过 HTTPS 连接,而代理以明文 HTTP 与后端服务器通信),这一点尤为关键。应用需要知道原始协议才能生成正确的链接(例如使用 https:// 而非 http://)。
示例:
客户端通过 HTTPS 连接到负载均衡器。负载均衡器通过 HTTP 连接到后端。
X-Forwarded-Proto: https
X-Real-IP
这是另一个事实标准的头字段,常被 NGINX 用来传递原始客户端的 IP 地址。与 X-Forwarded-For 不同,它通常只包含单个 IP 地址——原始客户端的地址,或紧邻的上游可信代理的地址。它通常由链路中的第一个代理在校验 X-Forwarded-For 头之后设置。
示例:
X-Real-IP: 192.0.2.1
实际影响与使用场景
在涉及代理、负载均衡器和 CDN 的现代 Web 架构中,代理头对于正常运行和安全性都至关重要。
- 日志与分析:准确的客户端 IP 地址对于 Web 服务器访问日志、流量分析和用户行为跟踪必不可少。
- 安全:
- 基于 IP 的访问控制:根据客户端 IP 地址限制对特定资源的访问。
- 速率限制:通过限制每个客户端 IP 的请求量来防止滥用或 DDoS 攻击。
- Web 应用防火墙(WAF):依据原始客户端的身份应用安全规则。
- 地理定位:确定用户的地理位置,用于内容定制或合规要求。
- 应用逻辑:
- URL 生成:应用需要
X-Forwarded-Host和X-Forwarded-Proto来构造与客户端原始请求相符的正确绝对 URL(例如用于重定向或应用内链接)。 - 会话管理:某些会话机制可能与 IP 地址绑定。
- 多租户应用:依据原始
Host头区分租户。
- URL 生成:应用需要
- 调试与排障:
Via头和完整的X-Forwarded-For链有助于诊断网络路径问题并定位有故障的代理。
代理配置与安全最佳实践
正确配置代理以处理这些头字段至关重要。
- 信任边界:只信任来自已知且可信的上游代理的
X-Forwarded-For(或Forwarded)条目。实现相应逻辑来解析该头、识别可信代理 IP,并从最右侧的不可信条目推导出真实客户端 IP。 - 剥离/清洗头字段:对于对外的代理,可考虑剥离或清洗
Via头以及任何内部自定义的X-头,以防泄露内部网络拓扑信息。 - 一致性:确保链路中所有代理和负载均衡器都以一致的方式配置,正确地追加或设置这些头字段。
- 标准与自定义:尽管
Forwarded才是标准,X-Forwarded-For、X-Forwarded-Host和X-Forwarded-Proto仍被广泛使用。具体实现通常两者兼容,或在Forwarded存在时优先使用它。
