X-Forwarded-For缺陷与陷阱 - 简书

标签: | 发表时间:2019-04-26 20:52 | 作者:
出处:https://www.jianshu.com

一、定义

X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。

二、起源

X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。 Squid 缓存代理服务器的开发人员最早引入了这一HTTP头字段,并由IETF在Forwarded-For HTTP头字段标准化草案中正式提出。

三、格式

这一HTTP头一般格式如下:
X-Forwarded-For: client1, proxy1, proxy2, proxy3

其中的值通过一个 逗号+空格 把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。 在上面这个例子中,这个请求成功通过了3台代理服务器:proxy1, proxy2 及 proxy3。请求由client1发出,到达了proxy3(proxy3可能是请求的终点)。请求刚从client1中发出时,XFF是空的,请求被发往proxy1;通过proxy1的时候,client1被添加到XFF中,之后请求被发往proxy2;通过proxy2的时候,proxy1被添加到XFF中,之后请求被发往proxy3;通过proxy3时,proxy2被添加到XFF中,之后请求的的去向不明,如果proxy3不是请求终点,请求会被继续转发。

四、来源IP可信吗?

因为伪造这一字段非常容易,所以应该谨慎使用X-Forwarded-For字段。正常情况下XFF中最后一个IP地址是最后一个代理服务器的IP地址, 这通常是一个比较可靠的信息来源。下面会详细说明,在什么情况下,这个信息并不准确。

1. 客户端设置代理

如果客户端使用了http代理(一般大公司内部上网都需要使用代理),同时,这个代理并没有正确设置(也可能是故意不设置)XFF,那么,XFF中client1的位置就会被http代理的ip取代,那么我们就无法正确获取客户端的真实IP。

2. 网络NAT设备

为了减缓可用的IP地址空间的枯竭, 大多数ISP网络或者公司网络中都会使用NAT设备,这样,一个公司或者一个小区的用户就可以共享使用一个IP来实现上网需求。NAT设备工作在IP层和TCP层,所以XFF不管怎么设置也无法解决这个问题。
这种情况下,我们也无法拿到客户的真实IP。

查看真实IP

Windows:

      无线局域网适配器 无线网络连接:

   连接特定的 DNS 后缀 . . . . . . . : lan
   描述. . . . . . . . . . . . . . . : Intel(R) Centrino(R) Wireless-N 1000
   物理地址. . . . . . . . . . . . . : 00-1E-64-91-DF-00
   DHCP 已启用 . . . . . . . . . . . : 是
   自动配置已启用. . . . . . . . . . : 是
   本地链接 IPv6 地址. . . . . . . . : fe80::7d79:4d1d:58e6:32cc%12(首选)
   IPv4 地址 . . . . . . . . . . . . : 192.168.1.186(首选)
   子网掩码  . . . . . . . . . . . . : 255.255.255.0
   获得租约的时间  . . . . . . . . . : 2016年9月9日 20:45:08
   租约过期的时间  . . . . . . . . . : 2016年9月12日 0:01:30
   默认网关. . . . . . . . . . . . . : 192.168.1.1
   DHCP 服务器 . . . . . . . . . . . : 192.168.1.1
   DHCPv6 IAID . . . . . . . . . . . : 201334372
   DHCPv6 客户端 DUID  . . . . . . . : 00-01-00-01-1D-69-C7-A1-00-27-13-65-48-AE

   DNS 服务器  . . . . . . . . . . . : 8.8.8.8
   TCPIP 上的 NetBIOS  . . . . . . . : 已启用

以太网适配器 本地连接:

   媒体状态  . . . . . . . . . . . . : 媒体已断开
   连接特定的 DNS 后缀 . . . . . . . :
   描述. . . . . . . . . . . . . . . : Intel(R) 82567LF Gigabit Network Connecti
on
   物理地址. . . . . . . . . . . . . : 00-27-13-65-48-AE
   DHCP 已启用 . . . . . . . . . . . : 是
   自动配置已启用. . . . . . . . . . : 是

Linux

      [root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eno16777728: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:42:15:de brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.248/24 brd 192.168.1.255 scope global dynamic eno16777728
       valid_lft 38029sec preferred_lft 38029sec
    inet6 fe80::20c:29ff:fe42:15de/64 scope link 
       valid_lft forever preferred_lft forever

查看自己的公网IP

访问以下两个网址,返回的网页会告诉你,你的公网IP是多少

可以用curl访问网址,举个例子

      [root@localhost ~]# curl http://www.ip.cn
当前 IP:223.72.90.206 来自:北京市 移动

结果,我的真实ip是192.168.1.186(私有IP),但是在XFF中会显示我的IP为223.72.90.206。

3. 后端服务购买安全服务

有的公司使用 加速乐, 我们可以认为使用这种服务后,相当于增加了一层http代理。

DNS是否被“主动劫持”

我们可以查看一下域名是否使用了加速乐(查看其他的安全服务也是类似的方法)

      [root@localhost ~]# dig www.XXXXXX.com

; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> www.51kahui.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31138
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.51kahui.com.       IN  A

;; ANSWER SECTION:
www.XXXXXX.com. 600 IN  CNAME   a29dXXXXXXa8f83b.cdn.jiashule.com.
a29dXXXXXXa8f83b.cdn.jiashule.com. 4 IN A   111.13.147.215
a29dXXXXXXa8f83b.cdn.jiashule.com. 4 IN A   111.13.147.195

结果,XFF中有一层proxy就是加速乐的IP,由于加速乐有很多节点,所以这个IP地址新并不是固定的。内部消息显示加速乐节点的IP要达到上万个,尽管我太想相信。但是这至少说明一点,就是XFF中proxy的IP地址是多变的。

是否被动注入安全服务

最近测试发现,使用电信4G网络的时候,XFF会莫名其妙的加入多个proxy代理,但是这个IP地址实在是无法查证,我们姑且认为他们也是一种安全服务吧

4. 攻击者

攻击者可以很容易伪造XFF,在发出请求时在XFF值中插入多个IP地址,以混淆服务端获取到客户端的真实IP。

结论,从XFF中的获取到的客户端IP地址并不可信,在使用各种ACL策略的时候,需要读者权衡利弊来满足业务需求。

五、Nginx中获取客户端IP的正确姿势

nginx目前在各个互联网公司中的标配, 其中ngx_http_realip_module模块就提供从XFF中实现获取用户的真实IP的功能。

配置方式

      set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.1.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

但是,上面的配置有一些问题,你发现什么问题了吗?

问题所在

首先,我们解释一下上面最后一条配置语句的含义

      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

实际上的含义是

      proxy_set_header  X-Forwarded-For '$X-Forwarded-For, $remote_addr';

我们可以看到,$proxy_add_x_forwarded_for等于$X-Forwarded-For加上$remote_addr。但是有一个问题,realip模块要比proxy模块运行的早,在realip模块中会把remote_addr重置为客户端IP,这样会导致 X-Forwarded-For设置错误。

我们拿proxy3为例,正常情况下,XFF传到proxy4服务时,XFF的值是

      client1, proxy1,proxy2

如果按照上面的配置的话,XFF值会是

      client1, proxy1,client1

如果内部有两级Nginx的话,XFF值会是

      client1, proxy1,client1,cleint1

总之,只要是XFF出现的重复的IP地址,就有理由怀疑是Nginx配置引起的。

下面是才是realip的正确配置

      set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.1.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

proxy_set_header X-Forwarded-For '$http_x_forwarded_for, $realip_remote_addr';

$realip_remote_addr是$remote_addr的副本信息,当realip模块修改了$remote_addr的值时,$realip_remote_addr用于保留$remote_addr的原始值。

六、从XFF中可以得到哪些确定的信息

假设有这样一个XFF

      X-Forwarded-For: client1, proxy1, proxy2, proxy3

其中,如果proxy2,proxy3是我们已知(可信)代理的话,我们可以确定proxy1的IP地址是可信的。

七、参考资料

相关 [forwarded for 陷阱] 推荐:

X-Forwarded-For缺陷与陷阱 - 简书

- -
X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项. 它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍. X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段.

好人陷阱

- Kenneth - 励志人生(LzTopic)
一个我喜欢的故事,再讲一次———. 某地发生凶案,迅速抓到杀人嫌犯,证人、证言一应俱全,就是他干的,他无论如何喊冤都没人听. 侥幸逃离的真凶也良心难受,于是他去向一个神父忏悔,说出来后,果然好多了. 可这神父受不了了,他只好去向另一个神父忏悔,以缓解自己承受的压力,每个知道这个邪恶秘密的神父都去找另一个神父忏悔,最后,全国的神父都知道了这个秘密.

效率的陷阱

- hikerlive - 《商业价值》杂志
效率不仅仅在于速度,更在于可持续. 7月中旬,与3G门户总裁张向东等一干朋友参与环青海湖骑行. 在海拔3200米的高原上,用4天时间骑行360多公里. 虽然明知保障车随时在后备用,但对于我们这些平时运动较少,缺乏骑行经验的人来说,也是一个不小的挑战. 挑战的不仅仅是心理和体力,更在于技术与习惯. 一如专业人士所言,长途骑行最大的挑战在于爬坡,而爬坡最大的挑战在于掌握骑行的节奏——也就是结合自身情况,对自行车的变速挡位之切换.

JavaScript 中的陷阱

- - CSDN博客Web前端推荐文章
JavaScript 通过函数管理作用域. 在函数内部声明的变量只在这个函数内部,函数外面不可用. 另一方面,全局变量就是在任何函数外面声明的或是未声明直接简单使用的. “未声明直接简单使用”,指的是不用  var 关键字来声明变量. 这个我们已经非常清楚,避免造成隐式产生全局变量的方法就是声明变量尽量用  var 关键字.

警惕电信陷阱

- md - 白板报
以下是我的亲身血泪教训,请转给你的所有至爱亲朋. 1、如果办理电信宽带,一定只办理固定宽带,任凭电信营业员巧舌如簧,也不要办理它们的套餐,任何套餐. 2、无线宽带一定不要用电信,丢失后被盗用,电信不管. 3、一定要采取预付费,千万不要后付费,事实证明,后付费就是电信设置的抢钱陷阱.

情景反射陷阱

- 烙饼 - 坏脾气的小肥
情景这个词,很多人称之为场景,都是一个意思. 我喜欢用“情景”,是因为场景的语感更偏重环境描述,而情景则附带有该环境下的直观感受这层意思. 最近一年,我带的几个项目有得有失,大都踩到了同一颗地雷,即“情景反射陷阱”. 这枚生造词的意思是,当用户接触到产品的时候印象尚可,但一旦关闭窗口,就很难想到再回来使用,缺乏刺激用户“再去用那款产品”的条件反射情景.

人生的三大陷阱

- nfwater - 小谈博客
三个小偷看见了,一个小偷说:“我去偷羊,叫农夫发现不了. ”另一个小偷说:“我要从农夫手里把驴偷走. ”第三个小偷说:“这都不难,我能把农夫身上的衣服全部偷来.   第一个小偷在道路的转弯处悄悄地走近山羊,把铃铛解了下来,拴到了驴尾巴上,然后把羊牵走了. 农夫四处环顾了一下,发现山羊不见了,就开始寻找.

Spring MVC Controller单例陷阱

- - 企业架构 - ITeye博客
Spring MVC Controller单例陷阱. 标签:Spring mvc. 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明. Spring MVC Controller默认是单例的:. 1、这个不用废话了,单例不用每次都new,当然快了. 2、不需要实例会让很多人迷惑,因为spring mvc官方也没明确说不可以多例.

张家界的旅游陷阱

- 琨中邪 - 月光微博客
  这次和人一起去张家界自助游三日,感想颇多,如果评点中国最能抢钱的旅游景点是哪个,我看非张家界莫属. 本来张家界很好的自然景点,被商业化糟蹋的一塌糊涂,旅游都成了景区被宰的羔羊.   通常游玩张家界的旅客都是3天时间,但张家界偏偏就不卖三日票,直接从两日票跳到周票,2日票的价格是245元,实际上根本不是48小时的票,如果你在第一天中午购票,只能玩一天半.

Java常见疑惑和陷阱(PPT)

- water - BlogJava-首页技术区
本来是打算小范围内讨论的,话题也比较小,后来听说人多了,临时拼凑些材料. 话题过大后重点就放在讲解上,其实这里面讲解的东东还是挺多的. 以后有时间会将并发完整整理一次. xylz 2010-12-03 16:13 发表评论.