我有后端 Web 服务器,它们通过 haproxy->nginx->fastcgi 接收请求。Web 应用程序过去常常看到 X-Forwarded-For 标头中有多个 IP,这些 IP 用逗号链接在一起(左侧是大多数原始 IP)。
在最近的某个时候(刚刚注意到,所以不确定是什么原因造成的)发生了一些变化,现在我只看到在标头中传递到我的 Web 应用程序的单个 IP。
我尝试使用 haproxy 1.4.21 和 1.4.22(最近升级),结果相同。Haproxy 有 forwardfor 标头设置:
option forwardfor
Nginx fastcgi_params 配置定义了要传递给应用程序的标头:
fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for;
有人知道这里可能出了什么问题吗?
编辑: 我刚刚开始在 nginx 日志中记录 $http_x_forwarded_for 变量,但 nginx 只看到一个 IP,这不应该是这种情况,因为我们应该始终看到我们的 haproxy ip 添加到其中,对吧?因此,问题要么出在 nginx 对传入变量的处理上,要么出在 haproxy 未正确构建它。我会继续深入研究...
编辑#2: 我在 HAProxy 中启用了请求和响应标头日志记录,但它没有为 X-Forwarded-For 输出任何内容,这看起来很奇怪:
10月10日 10:49:01 newark-lb1 haproxy[19989]: 66.87.95.74:47497 [2012年10月10日:10:49:01.467] http 服务/newark2 0/0/0/16/40 301 574 - - ---- 4/4/3/0/0 0/0{} {}“获取/2zi HTTP/1.1”
以下是我在前端为此设置的选项:
mode http
option httplog
capture request header X-Forwarded-For len 25
capture response header X-Forwarded-For len 25
option httpclose
option forwardfor
编辑#3:看起来 haproxy 确实在混淆标头,然后只将单个标头传递到后端。这对我们的生产服务影响很大,因此如果有人有想法,我们将不胜感激。我很困惑... :(
答案1
回答评论中的最后一个问题,XFF 中有一个以上的 IP 地址是正常的,此标头是值列表,代理通常会在此处添加其客户端的地址。由于长链中的每个人都在此处附加值,因此您的服务器必须以相反的顺序使用它们。例如,最后一个值将是服务器前面的 haproxy 实例添加的值,而前一个值将是 haproxy 之前的反向缓存添加的值,等等...
如果你不想让应用程序正确解析标头,你也可以要求 haproxy 在添加其自己的 XFF 标头之前将其删除:
reqidel ^X-Forwarded-For:
这样,服务器将只会获得 haproxy 添加的值,而 haproxy 将是 haproxy 的客户端。
答案2
我认为您在尝试使用 X-Forwarded-For 标头的方式上存在一些混淆。
首先,nginx 看到一个 IP 地址意味着 haproxy 正确添加了它。标头仅包含 haproxy 接收连接的源地址,因此在 nginx 日志中看不到 haproxy 的 IP 地址是正常的。
其次,您也不应该在传入请求中观察到 x-forwarded-for,因为只有一些传出代理会添加此标头,但一般建议在访问互联网时不要这样做。如果某些用户向您发送带有此类标头的请求,您会在 haproxy 的捕获中看到它,并且 nginx 将记录此值以及 haproxy 添加的客户端 IP。
我不明白的是您的第 3 点,因为您似乎假设标头必然存在于传入请求中,但根据 haproxy 的捕获和 nginx 日志判断,情况显然并非如此。我刚刚向您发送了一个带有“X-Forwarded-For:嗨,Jesse,我是 Willy”的请求,如果它可以帮助您排除故障,您应该会在 haproxy 和 nginx 日志中看到它。
可能的情况是,您之前习惯在那里看到多个地址,因为您的主要访问者之一正在使用添加了 XFF 标头的传出代理,或者因为您在 haproxy 前面有另一个反向代理(例如:apache、stunnel 等)。
顺便说一句,您应该将“option httpclose”替换为“option http-server-close”,它将启用客户端的保持活动功能并减少那些遇到高延迟的客户端的页面加载时间。