服务端获取用户的IP

背景:如果公司的网络扩扑图从统一的nginx转发过来的,需要在NG的配置文件里面配置:把用户实际的IP注入到请求头部的X-Forwarded-For ,然后应用程序去截取X-Forwarded-For中的内容来获取用户的实际IP。

判断是否内网的规定来自:




如果不用此方案的后果:用户的IP会被伪造,会存在很多衍生的漏洞

伪代码:

       1、从请求的head中读取X-Forwarded-For  ,然后按照逗号拆分为数组

       2、循环数据组(从0开始循环),读取第一个不是内网IP开头的IP即可。(所谓的内网IP是指10、172、192开头的某些IP)

       3、如果X-Forwarded-For 没有值,则从请求头里面的X-Real-IP来获取

java示例:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

	
public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if(ip!=null&&!"".equals(ip) && !"unKnown".equalsIgnoreCase(ip)){	
            //多次反向代理后会有多个ip值,第一个ip才是真实ip
            int index = ip.indexOf(",");
            if(index != -1){
            	String[] arrIp=ip.split(",");
            	for(String subIp:arrIp){
            		if(!checkInIp(subIp)){//找到第一个不是内部IP的进行返回
            			return subIp;
            		}
            	}
            }else{
                return ip;
            }
        }
        
        ip = request.getHeader("X-Real-IP");
        if(ip!=null&&!"".equals(ip)&& !"unKnown".equalsIgnoreCase(ip)){
            return ip;
        }
        
        ip = request.getHeader("PROXY_FORWARDED_FOR");
        if(ip!=null&&!"".equals(ip) && !"unKnown".equalsIgnoreCase(ip)){	
            //做下兼容
            int index = ip.indexOf(",");
            if(index != -1){
            	String[] arrIp=ip.split(",");
            	for(String subIp:arrIp){
            		if(!checkInIp(subIp)){//找到第一个不是内部IP的进行返回
            			return subIp;
            		}
            	}
            }else{
                return ip;
            }
        }
        
        return request.getRemoteAddr();
}

static String reg = "((192\\.168|172\\.([1][6-9]|[2]\\d|3[01]))"
                + "(\\.([2][0-4]\\d|[2][5][0-5]|[01]?\\d?\\d)){2}|"
                + "^(\\D)*10(\\.([2][0-4]\\d|[2][5][0-5]|[01]?\\d?\\d)){3})";
static Pattern p = Pattern.compile(reg);   // Instances of this class are immutable and are safe for use by multiple concurrent threads

/**
 * 判断是否为内网IP
 *  10.0.0.0 - 10.255.255.255 
 *  172.16.0.0 - 172.31.255.255 
 *  192.168.0.0 - 192.168.255.255
 * @param ip
 * @return
 *  注意:假如 ip 是 null,如返回 false 会误导使用者,因此抛出 NullPointerException
 */
public static boolean checkInIp(String ip) {
    Matcher matcher = p.matcher(ip);
    return matcher.find();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值