2018-09-25 如何取得wap和web用户的真实IP

https://blog.csdn.net/rogerjava/article/details/9418211

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-For: unknown

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代码:

package com.ecom;
 
import org.apache.commons.lang3.StringUtils;
 
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
 * Created with IntelliJ IDEA.
 * User: R
 * Date: 13-8-1
 * Time: 上午11:34
 * To change this template use File | Settings | File Templates.
 */
public class RealIpUtils {
 
    /**
     * 取所有IP段的私有IP段
     * A类  私有地址  10.0.0.0---10.255.255.255  保留地址 127.0.0.0---127.255.255.255
     * B类  私有地址 172.16.0.0-172.31.255.255
     * C类  私有地址 192.168.0.0-192.168.255.255
     * D类  地址不分网络地址和主机地址
     * E类  地址不分网络地址和主机地址
     */
    private static long aBegin = getIpNum("10.0.0.0");
    private static long aEnd = getIpNum("10.255.255.255");
    private static long bBegin = getIpNum("172.16.0.0");
    private static long bEnd = getIpNum("172.31.255.255");
    private static long cBegin = getIpNum("192.168.0.0");
    private static long cEnd = getIpNum("192.168.255.255");
    private static long saveBegin = getIpNum("127.0.0.0");
    private static long saveEnd = getIpNum("127.255.255.255");
 
    //跟IP有关需要做判断的header参数
    private static Set<String> ipHeaderNames = new HashSet<String>(){
        {
            add("clientip");//终端的IP即终端上网时动态分配的IP
            add("x-forwarded-for");//简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP
            add("proxy-client-ip");//代理客服端IP
            add("wl-proxy-client-ip");//WebLogic代理客服端IP(weblogic设置了才会有这个参数)
        }
    };
 
    public static String getRealIpAddr(HttpServletRequest request) {
 
        System.out.println("-------------getRealIpAddr start---------------------");
 
        //防止在header中的参数名有大小写之分,重新将需要处理的参数值和内容装填入Map中
        Map<String,String> ipHeaders = new HashMap<String,String>();
        Enumeration<String> headerNames = request.getHeaderNames();
        StringBuilder headerNamesStr = new StringBuilder();
        while (headerNames.hasMoreElements()){
            String nowName = headerNames.nextElement();
            headerNamesStr.append(nowName+",");
            if(ipHeaderNames.contains(nowName.toLowerCase())){
                ipHeaders.put(nowName.toLowerCase(),request.getHeader(nowName));//装填key和value
            }
        }
 
        System.out.println("headerNamesStr : "+headerNamesStr);
 
        //取正确的IP
        String ipAddress = null;
        ipAddress = ipHeaders.get("clientip");//取clientip与client-ip有区别
 
        System.out.println("clientip:"+ipAddress);
 
        if(ipAddress!=null&&isInnerIP(ipAddress)){//若取得的clientip是内网IP,则置为0
            ipAddress = null;
        }
 
        //若clientip为空或者是内网IP则取x-forwarded-for
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)){
            String xForwardedIpAddress = ipHeaders.get("x-forwarded-for");
            System.out.println("x-forwarded-for:"+ipAddress);
            //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (StringUtils.isNotEmpty(xForwardedIpAddress)) {
                String[] ipList = xForwardedIpAddress.split(",");
                for (String nowIp : ipList) {
                    if(isIpAddress(nowIp)&&!isInnerIP(nowIp)){//取第一个不是内网IP的IP作为真实IP
                        ipAddress = nowIp;
                        break;
                    }
                }
            }
        }
 
        //若x-forwarded-for为空则取proxy-client-ip
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = ipHeaders.get("proxy-client-ip");
            System.out.println("proxy-client-ip:"+ipAddress);
        }
 
        //若proxy-client-ip为空则取wl-proxy-client-ip
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = ipHeaders.get("wl-proxy-client-ip");
            System.out.println("wl-proxy-client-ip:"+ipAddress);
        }
 
        //若wl-proxy-client-ip为空则取RemoteAddr
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            System.out.println("remote-addr:"+ipAddress);
            if (ipAddress.equals("127.0.0.1")) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = inet.getHostAddress();
            }
        }
 
        System.out.println("real-ip:"+ipAddress);
 
        System.out.println("-------------getRealIpAddr end---------------------");
 
        return ipAddress;
    }
 
 
    public static boolean isInnerIP(String ipAddress) {
        boolean isInnerIp = false;
        long ipNum = getIpNum(ipAddress);
        isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || isInner(ipNum, saveBegin, saveEnd);
        return isInnerIp;
    }
 
    private static long getIpNum(String ipAddress) {
        String[] ip = ipAddress.split("\\.");
        long a = Integer.parseInt(ip[0]);
        long b = Integer.parseInt(ip[1]);
        long c = Integer.parseInt(ip[2]);
        long d = Integer.parseInt(ip[3]);
 
        long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
        return ipNum;
    }
 
    private static boolean isInner(long userIp, long begin, long end) {
        return (userIp >= begin) && (userIp <= end);
    }
 
 
    /**
     * 检验是否是合法的IP地址 * @param address String IP地址 * @return boolean IP地址是否合法
     */
    public static boolean isIpAddress(String address) {
        if(StringUtils.isEmpty(address)) return false;
        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))[.]"
                + "(((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))";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(address);
        return m.matches();
    }
}


本文来自 javaRoger 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/rogerjava/article/details/9418211?utm_source=copy

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,200评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,526评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,321评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,601评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,446评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,345评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,753评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,405评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,712评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,743评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,529评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,369评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,770评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,026评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,301评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,732评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,927评论 2 336

推荐阅读更多精彩内容