java HttpServletRequest -- 获取请求主机真实的IP地址(摘抄整理)

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

 

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

 

通过名字就知道,X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。

 

X-Forwarded-For 请求头格式非常简单,就这样:

 

X-Forwarded-For: client, proxy1, proxy2

可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。

 

request.getHeader("X-FORWARDED-FOR") 伪造这一字段非常容易,应该谨慎使用X-Forwarded-For字段

 

nginx 配置一

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

 

public class IpUtils {

    private static final Logger logger = LoggerFactory.getLogger(IpUtils.class);

    public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";

    public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");



    public static String longToIpV4(long longIp) {

        int octet3 = (int) ((longIp >> 24) % 256);

        int octet2 = (int) ((longIp >> 16) % 256);

        int octet1 = (int) ((longIp >> 8) % 256);

        int octet0 = (int) ((longIp) % 256);

        return octet3 + "." + octet2 + "." + octet1 + "." + octet0;

    }



    public static long ipV4ToLong(String ip) {

        String[] octets = ip.split("\\.");

        return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16)

                + (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);

    }



    public static boolean isIPv4Private(String ip) {

        long longIp = ipV4ToLong(ip);

        return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255"))

                || (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255"))

                || longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");

    }



    public static boolean isIPv4Valid(String ip) {

        return pattern.matcher(ip).matches();

    }



    /**

     * 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;

     *

     * @param request

     * @return

     */

    public final static String getIpAddress(HttpServletRequest request) {

        logger.info("IpUtils.getIpAddress is start");

        if (request == null){

            logger.info("IpUtils.getIpAddress request is null");

            return null;

        }



        String headerType = "X-Forwarded-For";

        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

                headerType = "Proxy-Client-IP";

                ip = request.getHeader("Proxy-Client-IP");

            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

                headerType = "WL-Proxy-Client-IP";

                ip = request.getHeader("WL-Proxy-Client-IP");

            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

                headerType = "HTTP_CLIENT_IP";

                ip = request.getHeader("HTTP_CLIENT_IP");

            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

                headerType = "HTTP_X_FORWARDED_FOR";

                ip = request.getHeader("HTTP_X_FORWARDED_FOR");

            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

                headerType = "getRemoteAddr";

                ip = request.getRemoteAddr();

            }

        } else if (ip.length() > 15) {

            String[] ips = ip.split(",");

            for (int index = 0; index < ips.length; index++) {

                String strIp = (String) ips[index];

                if (!("unknown".equalsIgnoreCase(strIp))) {

                    ip = strIp;

                    break;

                }

            }

        }

        logger.info("IpUtils.getIpAddress {} ip = {}",headerType,ip);



        if (isIPv4Valid(ip) && !isIPv4Private(ip)) {

            return ip;

        }

        return null;

    }

}

 

展开阅读全文

没有更多推荐了,返回首页