利用X-Forwarded-For伪造客户端IP漏洞成因及防范

阅读: 评论:0

利⽤X-Forwarded-For伪造客户端IP漏洞成因及防范
问题背景
在Web应⽤开发中,经常会需要获取客户端IP地址。⼀个典型的例⼦就是投票系统,为了防⽌刷票,需要限制每个IP地址只能投票⼀次。如何获取客户端IP
自由落体运动实验在Java中,获取客户端IP最直接的⽅式就是使⽤RemoteAddr()。这种⽅式能获取到连接服务器的客户端IP,在中间没有代理的情况下,的确是最简单有效的⽅式。但是⽬前互联⽹Web应⽤很少会将应⽤服务器直接对外提供服务,⼀般都会有⼀层Nginx做反向代理和负载均衡,有的甚⾄可能有多层代理。在有反向代理的情况下,直接使⽤RemoteAddr()获取到的IP地址是Nginx所在服务器的IP地址,⽽不是客户端的IP。
HTTP协议是基于TCP协议的,由于RemoteAddr()获取到的是TCP层直接连接的客户端的IP,对于Web应⽤服务器来说直接连接它的客户端实际上是Nginx,也就是TCP层是拿不到真实客户端的IP。
为了解决上⾯的问题,很多HTTP代理会在HTTP协议头中添加X-Forwarded-For头,⽤来追踪请求的来源。X-Forwarded-For的格式如下:X-Forwarded-For: client1, proxy1, proxy2
X-Forwarded-For包含多个IP地址,每个值通过逗号+空格分开,最左边(client1)是最原始客户端的IP地址,中间如果有多层代理,每⼀层代理会将连接它的客户端IP追加在X-Forwarded-For右边。
下⾯就是⼀种常⽤的获取客户端真实IP的⽅法,⾸先从HTTP头中获取X-Forwarded-For,如果X-Forwarded-For头存在就按逗号分隔取最左边第⼀个IP地址,不存在直接通过RemoteAddr()获取IP地址:
public String getClientIp(HttpServletRequest request) {
String xff = Header("X-Forwarded-For");
调直机防护罩if (xff == null) {
RemoteAddr();
} else {
ains(",") ? xff.split(",")[0] : xff;
}
}
另外,要让Nginx⽀持X-Forwarded-For头,需要配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
$proxy_add_x_forwarded_for会将和Nginx直接连接的客户端IP追加在请求原有X-Forwarded-For值的右边。
伪造X-Forwarded-For
⼀般的客户端(例如浏览器)发送HTTP请求是没有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地址,如果⼀个投票系统⽤这种⽅式做的IP限制,那么很容易会被刷票。
电梯门机
伪造X-Forwarded-For头的⽅法很简单,例如Postman就可以轻松做到:
Postman伪造X-Forwarded-For
外婆的厨房当然你也可以写⼀段刷票程序或者脚本,每次请求时添加X-Forwarded-For头并随机⽣成⼀个IP来实现刷票的⽬的。
如何防范
⽅法⼀
⽅法⼀:在直接对外的Nginx反向代理服务器上配置:
proxy_set_header X-Forwarded-For $remote_addr;
这⾥使⽤$remote_addr替代上⾯的$proxy_add_x_forwarded_for。$proxy_add_x_forwarded_for会在原有X-Forwarded-For上追加IP,这就相当于给了伪造X-Forwarded-For的机会。⽽$remote_addr是获取的是直接TCP连接的客户端IP(类似于Java中
的RemoteAddr()),这个是⽆法伪造的,即使客户端伪造也会被覆盖掉,⽽不是追加。
需要注意的是,如果有多层代理,那么只要在直接对外访问的Nginx上配置X-Forwarded-For为$remote_addr,内部层的Nginx还是要配置为$proxy_add_x_forwarded_for,不然内部层的Nginx⼜会覆盖掉客户端的真实IP。
ahp
⽅法⼆
另外⼀种⽅法是我在Tomcat源码中发现的:
实现思路:遍历X-Forwarded-For头中的IP地址,和上⾯⽅法不同的是,不是直接取左边第⼀个IP,⽽是从右向左遍历。遍历时可以根据正则表达式剔除掉内⽹IP和已知的代理服务器本⾝的IP(例如192.168开头的),那么拿到的第⼀个⾮剔除IP就会是⼀个可信任的客户端IP。这种⽅法的巧妙之处在于,即时伪造X-Forwarded-For,那么请求到达应⽤服务器时,伪造的IP也会在X-Forwarded-For值的左边,从右向左遍历就可以避免取到这些伪造的IP地址。这种⽅式本⽂就不提供具体实现代码了,有兴趣可以查看Tomcat源码。

本文发布于:2023-06-27 20:29:40,感谢您对本站的认可!

本文链接:https://patent.en369.cn/xueshu/138352.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:客户端   IP地址   请求
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 369专利查询检索平台 豫ICP备2021025688号-20 网站地图