在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

如果使用了反向代理软件,将http://192.168.1.110:2046/的URL反向代理为http://www.abc.com/的URL时,用request.getRemoteAddr()方法获取的IP地址是:127.0.0.1或192.168.1.110,而并不是客户端的真实IP。

经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。

当我们访问http://www.abc.com/index.jsp/时,其实并不是我们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问http://192.168.1.110:2046/index.jsp,代理服务器再将访问到的结果返回给我们的浏览器,因为是代理服务器去访问index.jsp的,所以index.jsp中通过request.getRemoteAddr()的方法获取的IP实际上是代理服务器的地址,并不是客户端的IP地址。

外界流传的JAVA/PHP服务器端获取客户端IP都是这么取的:

伪代码:

1)ip = request.getHeader(“X-FORWARDED-FOR “)

2)如果该值为空或数组长度为0或等于”unknown”,那么:
ip = request.getHeader(“Proxy-Client-IP”)

3)如果该值为空或数组长度为0或等于”unknown”,那么:
ip = request.getHeader(“WL-Proxy-Client-IP”)

4)如果该值为空或数组长度为0或等于”unknown”,那么:
ip = request.getHeader(“HTTP_CLIENT_IP”)

5)如果该值为空或数组长度为0或等于”unknown”,那么:
ip = request.getHeader(“X-Real-IP”)

6)如果该值为空或数组长度为0或等于”unknown”,那么:
ip = request.getRemoteAddr ()

先说说这些请求头的意思

  • X-Forwarded-For

这是一个 Squid 开发的字段,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。

格式为X-Forwarded-For:client1,proxy1,proxy2,一般情况下,第一个ip为客户端真实ip,后面的为经过的代理服务器ip。现在大部分的代理都会加上这个请求头。

  • Proxy-Client-IP/WL- Proxy-Client-IP

这个一般是经过apache http服务器的请求才会有,用apache http做代理时一般会加上Proxy-Client-IP请求头,而WL-Proxy-Client-IP是他的weblogic插件加上的头。

  • HTTP_CLIENT_IP

有些代理服务器会加上此请求头。

  • X-Real-IP
    nginx代理一般会加上此请求头。

下面是一个参考获取客户端IP地址的方法:

public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.contains(",")) {
return ip.split(",")[];
} else {
return ip;
}
}
如果使用的是Druid连接池,可以参考使用:com.alibaba.druid.util.DruidWebUtils#getRemoteAddr方法,但这个是经过多级代理的IP地址,需要自己处理下获取第一个。

有几点要注意

  1. 这些请求头都不是http协议里的标准请求头,也就是说这个是各个代理服务器自己规定的表示客户端地址的请求头。如果哪天有一个代理服务器软件用oooo-client-ip这个请求头代表客户端请求,那上面的代码就不行了。

  2. 这些请求头不是代理服务器一定会带上的,网络上的很多匿名代理就没有这些请求头,所以获取到的客户端ip不一定是真实的客户端ip。代理服务器一般都可以自定义请求头设置。

  3. 即使请求经过的代理都会按自己的规范附上代理请求头,上面的代码也不能确保获得的一定是客户端ip。不同的网络架构,判断请求头的顺序是不一样的。

  4. 最重要的一点,请求头都是可以伪造的。如果一些对客户端校验较严格的应用(比如投票)要获取客户端ip,应该直接使用ip=request.getRemoteAddr(),虽然获取到的可能是代理的ip而不是客户端的ip,但这个获取到的ip基本上是不可能伪造的,也就杜绝了刷票的可能。(有分析说arp欺骗+syn有可能伪造此ip,如果真的可以,这是所有基于TCP协议都存在的漏洞),这个ip是tcp连接里的ip。

参考
http://blog.csdn.net/sgx425021234/article/details/19043459
http://blog.csdn.net/fengwind1/article/details/51992528

Java正确获取客户端真实IP方法整理的更多相关文章

  1. 干货:Java正确获取客户端真实IP方法整理

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  2. Java Web 获取客户端真实IP

    Java Web 获取客户端真实IP 发生的场景:服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等情况,在进行客户端IP限定的时候,需要首先获取该真实的IP.一般分为两种情况: 方 ...

  3. Nginx反向代理后应用程序获取客户端真实IP

    Nginx反向代理后,Servlet应用通过request.getRemoteAddr()取到的IP是Nginx的IP地址,并非客户端真实IP,通过request.getRequestURL()获取的 ...

  4. 获取客户端用户真实ip方法整理(jekyll迁移)

    layout: post title: 获取客户端用户真实ip方法整理 date: 2019-08-22 author: xiepl1997 tags: springboot 由请求获取客户端ip地址 ...

  5. Java 获取客户端真实IP地址

    本文基于方法 HttpServletRequest.getHeader 和 HttpServletRequest.getRemoteAddr 介绍如何在服务器端获取客户端真实IP地址. 业务背景 服务 ...

  6. 获取客户端真实IP地址

    Java-Web获取客户端真实IP: 发生的场景:服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等情况,在进行客户端IP限定的时候,需要首先获取该真实的IP. 一般分为两种情况: ...

  7. 伪造IP及获取客户端真实IP地址

    Fiddler支持自定义规则,可以实现对HTTP请求数据发送给Server前或HTTP应答数据发送给浏览器前进行修改.下面的例子将演示如何向所有HTTP请求数据中增加一个头.1)打开Fiddler,点 ...

  8. java如何获取访问真实IP地址?

    java如何获取访问真实IP地址 解决方法: 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址,如果没有代理,则获取真实ip public static String getIp( ...

  9. Tomcat 8.5中获取客户端真实IP及协议

    获取客户端真实IP ServletRequest接口提供了getRemoteAddr方法用于获取客户端IP,但是当客户端通过代理服务器访问后端服务器的时候,服务器调用getRemoteAddr方法会返 ...

随机推荐

  1. linux下的用户组管理

    用户组管理分两类 如果赋给组什么权限,那么组员就会有什么权限 1.私有组 在创建新用户的时候,就要为用户指定组.如果没有指定,就会默认创建一个与用户名相同的用户组,这个用户组只有该用户一个用户,就被称 ...

  2. hdu 3518 Boring counting 后缀数组 height分组

    题目链接 题意 对于给定的字符串,求有多少个 不重叠的子串 出现次数 \(\geq 2\). 思路 枚举子串长度 \(len\),以此作为分界值来对 \(height\) 值进行划分. 显然,对于每一 ...

  3. PE笔记之PE文件总览图

  4. 归并排序Merge sort(转)

    原理,把原始数组分成若干子数组,对每一个子数组进行排序, 继续把子数组与子数组合并,合并后仍然有序,直到全部合并完,形成有序的数组 举例 无序数组[6 2 4 1 5 9] 先看一下每个步骤下的状态, ...

  5. formal parameter

    formal parameter : [3.16] object declared as part of a function declaration or definition that acqui ...

  6. LeetCode OJ-- 3Sum **

    https://oj.leetcode.com/problems/3sum/ 在一个数列中,求出所有3个数之和是0的3个数. 刚开始给自己挖了坑,由于没闹清,unique()函数的含义,去掉重复不彻底 ...

  7. 将Map<String, List<Map<String,Object>>>进行排序

    首先我贴上我的代码,刚开始我也不知道怎么排序还写了一些方法,最后请教群里的大神解决了 public Map<String, List<Map<String,Object>> ...

  8. Codeforces 506D Mr. Kitayuta's Colorful Graph(分块 + 并查集)

    题目链接  Mr. Kitayuta's Colorful Graph 把每种颜色分开来考虑. 所有的颜色分为两种:涉及的点的个数 $> \sqrt{n}$    涉及的点的个数 $<= ...

  9. mybatis反向工程

    首先创建一个test类: 在main方法里写上如下代码: List <String> warnings = new ArrayList <String>(); boolean ...

  10. java 读写操作

    java代码: 写入: public void getNotice(HttpServletRequest request, String notice){ String message = JSON. ...