转载:如何取得wap和web用户的真实IP

本文转载自:http://blog.youkuaiyun.com/rogerjava/article/details/9418211


1 HTTP_X_FORWARDED_FOR, REMOTE_ADDR,HTTP_CLIENT_IP和HTTP_VIA的区别总结

在移动互联网中,如何才能取得用户真正的IP呢,其实我们在header中可以得到的四个参数分别为REMOTE_ADDR ,HTTP_VIA ,HTTP_X_FORWARDED_FOR ,HTTP_CLIENT_IP,这四个参数意义如下:

REMOTE_ADDR  -  是你的客户端跟你的服务器“握手”时候的IP(访问客户端的 IP 地址)。如果使用了“匿名代理”,REMOTE_ADDR将显示代理服务器的IP,REMOTE_ADDR –访问客户端的 IP 地址,有可能是用户的IP,也有可能是代理的IP。 

HTTP_CLIENT_IP -  是代理服务器发送的HTTP头,代理端的IP,可能存在,可伪造。如果是“超级匿名代理”,则返回none值。同样,REMOTE_ADDR也会被替换为这个代理服务器的IP。 

HTTP_X_FORWARDED_FOR -简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理(比如APACHE代理)或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。如果有该条信息, 说明您使用了代理服务器,地址就是后面的数值。可以伪造。标准格式如下:X-Forwarded-For: client1, proxy1, proxy2

HTTP_VIA - 如果有该条信息, 就证明您使用了代理服务器,代理服务器的地址就是后面的数值。 

1)没有使用代理服务器的情况:

      REMOTE_ADDR = 您的 IP

      HTTP_VIA = 没数值或不显示

      HTTP_CLIENT_IP = 没数值或不显示

      HTTP_X_FORWARDED_FOR = 没数值或不显示

2)使用透明代理服务器的情况:TransparentProxies

      REMOTE_ADDR = 最后一个代理服务器 IP

      HTTP_VIA = 代理服务器 IP

      HTTP_CLIENT_IP = 代理服务器 IP

      HTTP_X_FORWARDED_FOR = 您的真实 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   这类代理服务器还是将您的信息转发给您的访问对象,无法达到隐藏真实身份的目的。

3)使用普通匿名代理服务器的情况:AnonymousProxies

      REMOTE_ADDR = 最后一个代理服务器 IP

      HTTP_VIA = 代理服务器 IP

      HTTP_CLIENT_IP = 代理服务器 IP

      HTTP_X_FORWARDED_FOR = 代理服务器 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   隐藏了您的真实IP,但是向访问对象透露了您是使用代理服务器访问他们的。

4)使用欺骗性代理服务器的情况:DistortingProxies

      REMOTE_ADDR = 代理服务器 IP

      HTTP_VIA = 代理服务器 IP

      HTTP_CLIENT_IP = 代理服务器 IP

      HTTP_X_FORWARDED_FOR = 随机的 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   告诉了访问对象您使用了代理服务器,但编造了一个虚假的随机IP代替您的真实IP欺骗它。

5)使用高匿名代理服务器的情况:HighAnonymity Proxies (Elite proxies)

      REMOTE_ADDR = 代理服务器 IP

      HTTP_VIA = 没数值或不显示

      HTTP_CLIENT_IP = 没数值或不显示

      HTTP_X_FORWARDED_FOR = 没数值或不显示 ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

完全用代理服务器的信息替代了您的所有信息,就象您就是完全使用那台代理服务器直接访问对象。

6)使用了cdn内容分发网络

    由于访客不是直接访问源服务器,跟源服务打交道的都是CDN的节点机器,所以在源服务器抓取到的IP都是节点IP。这对按ip来统计的浏览量、网站统计等模块的影响会比较大。一般来说,CDN节点会以某种方式将源客户端的IP传递给源服务器,就拿我用的网宿CDN来说,它是将源IP添加到了一个叫“Cdn-Src-Ip”的Http Header里

注:Squid默认设置forwarded_for项默认是为on,如果 forwarded_for设成了 off 则:X-Forwarded-Forunknown


 

2 wap特有表头属性分析

Sky-Real-IP: Sky-Wapproxy的代理IP,是SKY WAP代理的请求

X-real-ip:    跟remote_addr一样,对nginx而言设置了则有不设置则无,一般nginx设置为 proxy_set_header  X-real-ip $remote_addr;

x-network-info  GPRS,10.139.155.216,13951615696,211.139.172.70,unsecured,移动的gprs网络信息,10.139.155.216和211.139.172.70都是WAP网关的IP,这次会话使用的是非安全的通信模式,即是没有使用安全服务层(TLS或者WTLS),13951615696是你们省网关的GT码

x-forwarded-for  10.139.155.216, 10.139.155.215 同HTTP_X_FORWARDED_FOR

x-source-id 连接模式,一般是本地局域网IP 

client-ip:终端的IP即终端上网时动态分配的IP(clientip)有可能是内网IP

clientip: 使用UCWEB时uc带上的客户端IP

 

3 关于Proxy-Client-IP和WL-Proxy-Client-IP

在apache+WebLogic整合系统中,apache会对request对象进行再包装,附加一些WLS要用的头信息,两个信息如下:

Proxy-Client-IP     代理客服端IP

WL-Proxy-Client-IP    WebLogic代理客服端IP(weblogic设置了才会有这个参数)

一般情况下Proxy-Client-IP和WL-Proxy-Client-IP的IP是一样的

在Linux加Squid的组合做为代理服务器的网络环境中,若Squid的配置forwarded_for 设成了 off则:X-Forwarded-For: unknown。此时在apache+WebLogic的系统中Proxy-Client-IP和WL-Proxy-Client-IP可以反应出用户的真实IP

 

4 如何取得用户真实的IP

综上所述:

正确的取得wap用户IP的逻辑应该是

1.      判断clientip是否为空,若不为空则取

2.      判断x-forwarded-for是否有值

3.      若有值判断是否是“unknown”若不是则此时用户IP为x-forwarded-for中第一个不为unknown且不是当前内网的IP。

4.      若x-forwarded-for无值或为“unknown”则看Proxy-Client-IP和WL-Proxy-Client-IP中是否有值,若有取此值,若无取REMOTE_ADDR作为用户IP

 

流程图如下:

 

下面是java代码:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.ecom;  
  2.   
  3. import org.apache.commons.lang3.StringUtils;  
  4.   
  5. import javax.servlet.http.HttpServletRequest;  
  6. import java.net.InetAddress;  
  7. import java.net.UnknownHostException;  
  8. import java.util.*;  
  9. import java.util.regex.Matcher;  
  10. import java.util.regex.Pattern;  
  11.   
  12. /** 
  13.  * Created with IntelliJ IDEA. 
  14.  * User: R 
  15.  * Date: 13-8-1 
  16.  * Time: 上午11:34 
  17.  * To change this template use File | Settings | File Templates. 
  18.  */  
  19. public class RealIpUtils {  
  20.   
  21.     /** 
  22.      * 取所有IP段的私有IP段 
  23.      * A类  私有地址  10.0.0.0---10.255.255.255  保留地址 127.0.0.0---127.255.255.255 
  24.      * B类  私有地址 172.16.0.0-172.31.255.255 
  25.      * C类  私有地址 192.168.0.0-192.168.255.255 
  26.      * D类  地址不分网络地址和主机地址 
  27.      * E类  地址不分网络地址和主机地址 
  28.      */  
  29.     private static long aBegin = getIpNum("10.0.0.0");  
  30.     private static long aEnd = getIpNum("10.255.255.255");  
  31.     private static long bBegin = getIpNum("172.16.0.0");  
  32.     private static long bEnd = getIpNum("172.31.255.255");  
  33.     private static long cBegin = getIpNum("192.168.0.0");  
  34.     private static long cEnd = getIpNum("192.168.255.255");  
  35.     private static long saveBegin = getIpNum("127.0.0.0");  
  36.     private static long saveEnd = getIpNum("127.255.255.255");  
  37.   
  38.     //跟IP有关需要做判断的header参数  
  39.     private static Set<String> ipHeaderNames = new HashSet<String>(){  
  40.         {  
  41.             add("clientip");//终端的IP即终端上网时动态分配的IP  
  42.             add("x-forwarded-for");//简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP  
  43.             add("proxy-client-ip");//代理客服端IP  
  44.             add("wl-proxy-client-ip");//WebLogic代理客服端IP(weblogic设置了才会有这个参数)  
  45.         }  
  46.     };  
  47.   
  48.     public static String getRealIpAddr(HttpServletRequest request) {  
  49.   
  50.         System.out.println("-------------getRealIpAddr start---------------------");  
  51.   
  52.         //防止在header中的参数名有大小写之分,重新将需要处理的参数值和内容装填入Map中  
  53.         Map<String,String> ipHeaders = new HashMap<String,String>();  
  54.         Enumeration<String> headerNames = request.getHeaderNames();  
  55.         StringBuilder headerNamesStr = new StringBuilder();  
  56.         while (headerNames.hasMoreElements()){  
  57.             String nowName = headerNames.nextElement();  
  58.             headerNamesStr.append(nowName+",");  
  59.             if(ipHeaderNames.contains(nowName.toLowerCase())){  
  60.                 ipHeaders.put(nowName.toLowerCase(),request.getHeader(nowName));//装填key和value  
  61.             }  
  62.         }  
  63.   
  64.         System.out.println("headerNamesStr : "+headerNamesStr);  
  65.   
  66.         //取正确的IP  
  67.         String ipAddress = null;  
  68.         ipAddress = ipHeaders.get("clientip");//取clientip与client-ip有区别  
  69.   
  70.         System.out.println("clientip:"+ipAddress);  
  71.   
  72.         if(ipAddress!=null&&isInnerIP(ipAddress)){//若取得的clientip是内网IP,则置为0  
  73.             ipAddress = null;  
  74.         }  
  75.   
  76.         //若clientip为空或者是内网IP则取x-forwarded-for  
  77.         if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)){  
  78.             String xForwardedIpAddress = ipHeaders.get("x-forwarded-for");  
  79.             System.out.println("x-forwarded-for:"+ipAddress);  
  80.             //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割  
  81.             if (StringUtils.isNotEmpty(xForwardedIpAddress)) {  
  82.                 String[] ipList = xForwardedIpAddress.split(",");  
  83.                 for (String nowIp : ipList) {  
  84.                     if(isIpAddress(nowIp)&&!isInnerIP(nowIp)){//取第一个不是内网IP的IP作为真实IP  
  85.                         ipAddress = nowIp;  
  86.                         break;  
  87.                     }  
  88.                 }  
  89.             }  
  90.         }  
  91.   
  92.         //若x-forwarded-for为空则取proxy-client-ip  
  93.         if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
  94.             ipAddress = ipHeaders.get("proxy-client-ip");  
  95.             System.out.println("proxy-client-ip:"+ipAddress);  
  96.         }  
  97.   
  98.         //若proxy-client-ip为空则取wl-proxy-client-ip  
  99.         if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
  100.             ipAddress = ipHeaders.get("wl-proxy-client-ip");  
  101.             System.out.println("wl-proxy-client-ip:"+ipAddress);  
  102.         }  
  103.   
  104.         //若wl-proxy-client-ip为空则取RemoteAddr  
  105.         if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
  106.             ipAddress = request.getRemoteAddr();  
  107.             System.out.println("remote-addr:"+ipAddress);  
  108.             if (ipAddress.equals("127.0.0.1")) {  
  109.                 //根据网卡取本机配置的IP  
  110.                 InetAddress inet = null;  
  111.                 try {  
  112.                     inet = InetAddress.getLocalHost();  
  113.                 } catch (UnknownHostException e) {  
  114.                     e.printStackTrace();  
  115.                 }  
  116.                 ipAddress = inet.getHostAddress();  
  117.             }  
  118.         }  
  119.   
  120.         System.out.println("real-ip:"+ipAddress);  
  121.   
  122.         System.out.println("-------------getRealIpAddr end---------------------");  
  123.   
  124.         return ipAddress;  
  125.     }  
  126.   
  127.   
  128.     public static boolean isInnerIP(String ipAddress) {  
  129.         boolean isInnerIp = false;  
  130.         long ipNum = getIpNum(ipAddress);  
  131.         isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || isInner(ipNum, saveBegin, saveEnd);  
  132.         return isInnerIp;  
  133.     }  
  134.   
  135.     private static long getIpNum(String ipAddress) {  
  136.         String[] ip = ipAddress.split("\\.");  
  137.         long a = Integer.parseInt(ip[0]);  
  138.         long b = Integer.parseInt(ip[1]);  
  139.         long c = Integer.parseInt(ip[2]);  
  140.         long d = Integer.parseInt(ip[3]);  
  141.   
  142.         long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;  
  143.         return ipNum;  
  144.     }  
  145.   
  146.     private static boolean isInner(long userIp, long begin, long end) {  
  147.         return (userIp >= begin) && (userIp <= end);  
  148.     }  
  149.   
  150.   
  151.     /** 
  152.      * 检验是否是合法的IP地址 * @param address String IP地址 * @return boolean IP地址是否合法 
  153.      */  
  154.     public static boolean isIpAddress(String address) {  
  155.         if(StringUtils.isEmpty(address)) return false;  
  156.         String regex = "(((2[0-4]d)|(25[0-5]))|(1d{2})|([1-9]d)|(d))[.](((2[0-4]d)|(25[0-5]))|(1d{2})|([1-9]d)|(d))[.]"  
  157.                 + "(((2[0-4]d)|(25[0-5]))|(1d{2})|([1-9]d)|(d))[.](((2[0-4]d)|(25[0-5]))|(1d{2})|([1-9]d)|(d))";  
  158.         Pattern p = Pattern.compile(regex);  
  159.         Matcher m = p.matcher(address);  
  160.         return m.matches();  
  161.     }  
  162. }  

简单一点的代码:

/**
	 * 获取访问网站的机器的iP地址
	 * @param request  HttpServletRequest
	 * @return String ip地址字符串
	 */
	public static String getIpAddr(HttpServletRequest request) {  
		String ip = request.getHeader("x-forwarded-for");  
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
			ip = request.getHeader("Proxy-Client-IP");  
		}  
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
			ip = request.getHeader("WL-Proxy-Client-IP");  
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
			ip = request.getRemoteAddr();  
		}
		return ip;  
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值