Java面试之如何获取客户端真实IP
前言
在进行一些小游戏开发时,我们经常比较关注的一个功能便是分享。针对分享,我们希望能根据各个城市或者地区,能有不同的分享文案,辨识地区的功能如果由服务器来完成的话,我们就需要知道客户端的真实IP。今天我们就来看看服务器是如何获取到客户端的真实IP的。
nginx配置
首先,一个请求肯定是可以分为请求头和请求体的,而我们客户端的IP地址信息一般都是存储在请求头里的。如果你的服务器有用Nginx做负载均衡的话,你需要在你的location里面配置X-Real-IP和X-Forwarded-For请求头:
location^~/your-service/{ proxy_set_headerX-Real-IP$remote_addr; proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for; proxy_passhttp://localhost:60000/your-service/; }
X-Real-IP
在《实战nginx》中,有这么一句话:
经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址。
这句话的意思是说,当你使用了nginx反向服务器后,在web端使用request.getRemoteAddr()(本质上就是获取$remote_addr),取得的是nginx的地址,即$remote_addr变量中封装的是nginx的地址,当然是没法获得用户的真实ip的。但是,nginx是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx里作一个赋值操作,即我在上面的配置:
proxy_set_headerX-Real-IP$remote_addr;
X-Forwarded-For
X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是client1,proxy1,proxy2以逗号隔开各个地址,由于它是非rfc标准,所以默认是没有的,需要强制添加。在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip。也就是说在默认情况下我们使用request.getAttribute("X-Forwarded-For")获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,我们需要自己在nginx添加配置:
proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;
意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。
那么$proxy_add_x_forwarded_for又是什么?
$proxy_add_x_forwarded_for变量包含客户端请求头中的X-Forwarded-For与$remote_addr两部分,他们之间用逗号分开。
举个例子,有一个web应用,在它之前通过了两个nginx转发,www.linuxidc.com即用户访问该web通过两台nginx。
在第一台nginx中,使用:
proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量的X-Forwarded-For部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。
到了第二台nginx,使用:
proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”,这样就清楚了吧。
服务器获取真实IP
代码为:
publicstaticStringgetIpAddress(HttpServletRequestrequest){ StringXip=request.getHeader("X-Real-IP"); StringXFor=request.getHeader("X-Forwarded-For"); if(!Strings.isNullOrEmpty(XFor)&&!"unKnown".equalsIgnoreCase(XFor)){ //多次反向代理后会有多个ip值,第一个ip才是真实ip intindex=XFor.indexOf(","); if(index!=-1){ returnXFor.substring(0,index); }else{ returnXFor; } } XFor=Xip; if(!Strings.isNullOrEmpty(XFor)&&!"unKnown".equalsIgnoreCase(XFor)){ returnXFor; } if(Strings.nullToEmpty(XFor).trim().isEmpty()||"unknown".equalsIgnoreCase(XFor)){ XFor=request.getHeader("Proxy-Client-IP"); } if(Strings.nullToEmpty(XFor).trim().isEmpty()||"unknown".equalsIgnoreCase(XFor)){ XFor=request.getHeader("WL-Proxy-Client-IP"); } if(Strings.nullToEmpty(XFor).trim().isEmpty()||"unknown".equalsIgnoreCase(XFor)){ XFor=request.getHeader("HTTP_CLIENT_IP"); } if(Strings.nullToEmpty(XFor).trim().isEmpty()||"unknown".equalsIgnoreCase(XFor)){ XFor=request.getHeader("HTTP_X_FORWARDED_FOR"); } if(Strings.nullToEmpty(XFor).trim().isEmpty()||"unknown".equalsIgnoreCase(XFor)){ XFor=request.getRemoteAddr(); } returnXFor; }
我们来看看各个请求头的含义
X-Real-IP
nginx代理一般会加上此请求头。
X-FORWARDED-FOR
这是一个Squid开发的字段,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。
Proxy-Client-IP和WL-Proxy-Client-IP
这个一般是经过apachehttp服务器的请求才会有,用apachehttp做代理时一般会加上Proxy-Client-IP请求头,而WL-Proxy-Client-IP是它的weblogic插件加上的头。
HTTP_CLIENT_IP
有些代理服务器会加上此请求头。在网上搜了一下,有一个说法是:
这是普通的httpheader,伪造起来很容易,不要轻易信任用户输入。
curl-H'client-ip:8.8.8.8'lidian.club/phpinfo.php|grep_SERVER
你就能看到_SERVER["HTTP_CLIENT_IP"]了。client-ip和client-host是在NAPT还没普及的年代,企业内网假设的http透明代理,传给服务器的header,只有极少数厂家用过,从来不是标准,也从来没成为过事实标准。
(大家最熟悉的事实标准就是x-forwarded-for)后来出现的webproxy也没见用过这个header。
TCP/IPIllustratedVol3没有讲过这个header,网上的传言不可信。
可考的最早痕迹出现在2005年,日本一部Perl/CGI秘籍(9784798010779,270页)通过client-ip与via两个header屏蔽代理用户访问。
HTTP_X_FORWARDED_FOR
简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP代理(比如APACHE代理)或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。如果有该条信息,说明您使用了代理服务器,地址就是后面的数值。可以伪造。标准格式如下:X-Forwarded-For:client1,proxy1,proxy2
总结
以上就是我在处理客户端真实IP的方法,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。