X-Forwarded-for漏洞解析
阅读原文时间:2023年07月08日阅读:2

首先了解X-Forwarded-for(简称:XFF)

X-Forwarded-for:简称XFF,它代表客户端,也就是HTTP的请求真实的IP,只有在通过了HTTP代理
或者负载均衡器时才会添加该项。它不是RFC中定义的标准请求头信息,Squid 缓存代理服务器的开发人
员最早引入了这一HTTP头字段,在squid缓存代理服务器开发文档中可以找到详细的介绍。
360百度百科:请点击链接https://baike.so.com/doc/7045641-7268547.html)
==============================================================
一、产生背景00
X-Forwarded-For是用来识别通过HTTP代理或负载均衡方式连接到WEB服务器的客户端最原始的
ip地址请求字段。
获取客户端ip地址的常用方法有两种①Remote Address ②X-Forwarded-for
在java中,获取客户端ip地址最简单的方式就是request.getRemoteAddr()——即第一种。这种方
式能直接获取到连接服务器的客户端ip,“在中间没有代理的情况下,的确是最简单有效的方式”。但
是目前互联网web应用很少会将应用服务器直接对外服务,有的甚至可能有多层代理。在有反向代理的
情况下直接使用request.getRemoteAddr(),获取到的ip地址是Nginx(或其他的代理服务器的ip地址)
,而不是客户端的ip地址。而HTTP协议是基于TCP协议的,由于request.getRemoteAddr()获取到的
是TCP层直连的客户端ip,对于web应用服务器来说直接连接它的客户端实际上是Nginx,也就是说TCP
层是拿不到真是的客户端的ip的。
为了解决上面的问题,很多HTTP代理会在HTTP协议头中添加 X-Forwarded-for头,用于追踪请求
来源最真实的ip地址。
-----------------------------------------------------------------------------------------------------
二、格式:
该HTTP头一般如下:
X-Forwarded-For:client1,proxy1,proxy2,proxy3
服务端收到的信息:X-Forwarded-For:IP0,IP1,IP2

三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0
其中实物值通过一个 逗号+空格 把多个IP地址区分隔开,最左边(client1)是最原始客户端的IP地址
代理服务器每成功收到一个请求,就把 《“请求来源的IP地址”》添加到右边。在上面的例子中,这个
请求成功通过了三台代理服务器:proxy1,proxy2,proxy3。
注意:①添加的是“请求来源的IP地址”
②是“添加ip地址”而不是“覆盖ip地址”
③列表中之所以没有IP3,是因为proxy3直连服务器,他会给XFF追加IP2,表示它是在帮proxy
2转发请求,而IP3可以在服务端通过Remote Address 字段获得。由于HTTP是基于TCP连
接,HTTP协议中没有IP的概念,Remote Address 来自于TCP 连接,表示与服务器建立TCP
连接的设备IP,在这个例子里就是 IP3。
@具体的请求过程:在请求刚从client1中发出的时候,XFF是空的,当请求“通过”第一个
代理的时候,由于添加的是“请求来源的IP地址”,所以该代理服务器会把客户端/浏览器的IP
地址(即最原始的IP地址)添加为client1;当“通过”第二个代理的时候,由于添加的是“请求来源的IP
地址”,所以该代理服务器会把第一个代理的ip地址“添加”到proxy1;当通过第三个代理的时候,由
于添加的是“请求来源的IP地址”,所以该代理服务器会把第二个代理的IP地址“添加”到proxy2;。

从该过程便可以发现:由于添加的是“请求来源的IP地址”,所以导致在“第一个代理处”添加“最
原始的ip地址”,在“第二个代理”处添加“第一个代理的ip地址”。。这样的错位的关系。
-----------------------------------------------------------------------------------------------------
三、简单用法举例:
public String getClientIp(HttpServletRequest request) {
    String xff = request.getHeader("X-Forwarded-For");
  if (xff == null) {
    return request.getRemoteAddr();
  } else {
    return xff.contains(",") ? xff.split(",")[0] : xff;
  }
}
---------------------
另外,要让Nginx支持X-Forwarded-For头,需要配置:
roxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
以上就是一种常用的获取客户端真实ip的方法:首先从HTTP头中获取X-Forwarded-For,如果X-Forwarded-For
头存在就按逗号分隔取“最左边”第一个ip的地址,不存在就直接通过request.getRemoteAddr()获取ip地址
$proxy_add_x_forwarded_for会将和Nginx直接连接的客户端ip追加在原有的X-Forwarded-For值得
右边。
注意:在使用X-Forwarded-For获取ip是,默认获取的是最左边的值(即client1)
-------------------------------------------------------------------------------------------------------
四、利用X-Forwarded-For伪造客户端ip漏洞:
首先,Remote Address是无法伪造的,因为是直接从TCP连接信息中获取到的,而建立TCP连接需要
三次握手,如果伪造了源ip,便无法建立TCP连接,更不会有后面的HTTP请求。
但是,X-Forwarded-For头是可以伪造的。
一般的客户端(eg:浏览器)在发送请求的时候是没有X-Forwarded-For头的,当请求到达第一个代理
服务器的时候,代理服务器会加上X-Forwarded-For请求头,并将值设为客户端的ip地址(也就是最左边
的第一个值),后面如果还有多个代理,会依次将ip追加到X-Forwarded-For都的最右边,最终请求到达
web应用服务器,应用通过获取X-Forwarded-For头取左边第一个ip即为客户端真实ip
但是如果客户端在发送请求时,在请求头上带上一个伪造的X-Forwarded-For,由于后续每层代理只
会追加为不会代理,那么最终到达应用服务器时,获取的左边第一个ip地址将会是客户端伪造的ip。也就
是上面的java代码中getClientIp()方法获取的ip地址很有可能是伪造的ip地址,如果没有加以限制,则会
造成巨大的安全隐患
可以利用工具Postman或burpsuite进行XFF攻击%e6%b5%85%e6%98%93%e6%b7%b1
-------------------------------------------------------------------------------------------------------
五、如何防范(略)
==============================================================
CTF----管理员系统:(再此使用的是burpsuite)
打开之后首先很容易想到是sql注入,但是在输入值并submit之后发现并不是,并且出现一句提示
“ip禁止访问,请联系本地管理员登录,ip已被记录”,发现在提示中有“本地管理员”,便想到:
可以伪装成本地访问。
另外,通过看源代码发现在最底部有一条用base64编码的注释,解码得到“text123”,由于是用管理员
登录,所以用户名应该是admin,那么text123就应该是密码了
然后
使用burpsuite进行抓包,发送到Repeater进行改包:即在Headers中添加一对键值对:X-Forwarded-
For:127.0.0.1,在GO一下,就可以得到flag了。