【背景】
在运维工作中,经常会遇到X-Forwarded-For 这个字段,比如nginx、haproxy、缓存代理、甚至好点的网络7层网络设备都可以修改这个字段,这个字段对记录客户端的真实IP地址非常有用,在分析nginx日志,haproxy日志中,经常利用这个字段统计访问的来源,并进一步分析问题
常见如下两个网络结构,从办公室用户通过公网访问一台webserver服务
这个事例是公司的一个用户(10.28.81.84)的用户通过网络出口公网地址是116.247.112.179 访问 公网地址是110.189.90.120的内部服务。其中经历了一台haproxy在代理到一台nginx web服务。
haproxy增加X-Forwarded-For的设置option forwardfor
:如果服务器上的应用程序想记录发起请求的客户端的IP地址,需要在HAProxy上配置此选项,这样HAProxy会把客户端的IP信息发送给服务器,在HTTP请求中添加"X-Forwarded-For"字段。
X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。
标准格式如下:
X-Forwarded-For: client1, proxy1, proxy2
从标准格式可以看出,X-Forwarded-For头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡的ip地址,经过几个就会出现几个。
nginx增加X-Forwarded-For的设置
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
解释:
如果 set_real_ip_from 设置错误可能会导致如下现象(本机IP是 10.10.20.32 容器机IP)
#set_real_ip_from 10.0.0.0/8;
#set_real_ip_from 172.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
real_ip_header X-Forwarded-For;
这两个指令 来自 HttpRealipModule,表示把来在10.0.0.0/8 段的所有请求的来源地址,都改成 X-Forwarded-For 头中的最后一个IP,这时候新来源地址会赋给 remote_addr 变量;这里如果请求头没有 X-Forwarded-For 头 或者头是不合法IP,Nginx 不会对来源IP进行修改。
$proxy_add_x_forwarded_for
the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.
可以理解为$X-Forwarded-For,$remote_addr
用户访问
www.xxxxx.com
haproxy日志格式
%ci\ %si\ %[capture.req.hdr(1)]\
格式解释:
#HAProxy的日志记录内容配置
capture request header Host len 40 # 请求中的主机名
capture request header X-Forwarded-For len 100
日志格式:
%ci\ %si\ %[capture.req.hdr(1)]\
%ci:client_ip (accepted address) 客户端IP
%si: server_IP (target address)
日志:
116.247.112.179 10.10.20.34 -
可以看到haproxy获取的日志是
客户端IP是 116.247.112.179
后端server的IP地址是 10.10.20.34
X-Forwarded-For 为 -
nginx日志的格式
$request_time $upstream_response_time $remote_addr "$http_x_forwarded_for" - "$server_addr"
日志内容
0.135 0.135 116.247.112.179 "116.247.112.179" - "172.18.0.4" 0384682027257641
可见:$proxy_add_x_forwarded_for 的值为 116.247.112.179 且 $remote_addr 被赋值成了 116.247.112.179
haproxy日志:
日志:
116.247.112.179 10.10.20.34 10.28.81.84
可以看到haproxy获取的日志是
客户端IP是 116.247.112.179
后端server的IP地址是 10.10.20.34
X-Forwarded-For 为 10.28.81.84
疑问? 为啥公司的内网地址都变成 X-Forwarded-For ,因为公司的出口之前的那个代理设备加上了X-Forwarded-For 将地址客户的来源地址写入了 X-Forwarded-For http字段中去了
nginx日志
nginx日志的格式
$request_time $upstream_response_time $remote_addr "$http_x_forwarded_for" - "$server_addr"
日志内容
0.008 0.008 116.247.112.179 "10.28.81.84, 116.247.112.179" - "172.18.0.4"
可以看出 $http_x_forwarded_for 的值为 10.28.81.84, 116.247.112.179