Java gets the IP address, request.getHeader("x-forwarded-for")

Nginx configuration

After the front-end and back-end are separated, nginx is used as the static server, and the interface cross-domain is realized through the reverse proxy method. While reducing the development cost, it also brings many problems, such as the acquisition of the real IP of the client.

In some special scenarios, such as risk control and payment process, it is often necessary to obtain the user's ip information, but the nginx reverse proxy has completely changed the source of the server's request and isolated the connection between the user and the server while realizing cross-domain ,As shown below

When the user visits the front-end page ' https://a.test.com/index/html' and calls the payment interface, the address of the payment interface is 'https://a.test.com/goPay', and then reversed by nginx Proxy to 'https://b.test.com/goPay' on the server side . At this time, for the server side, the requests he receives are all from the nginx server, and the default IP obtained by the server side is the IP of the nginx server. This is not what we want. At this time, you need to add the following configuration:

 
 
  1. proxy_set_header X-Real-IP $remote_addr;

  2. proxy_set_header X-Real-Port $remote_port;

  3. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

The three headers represent:

 
 
  1. X-Real-IP 客户端ip

  2. X-Real-Port 客户端或上一级端口

  3. X-Forwarded-For 包含了客户端和各级代理ip的完整ip链路

Among them, X-Real-IP is required, and the last two items are optional. When there is only one level of nginx proxy, X-Real-IP and X-Forwarded-For are consistent, and when there are multiple levels of proxy, X-Forwarded-For becomes the following form

X-Forwarded-For: 客户端ip, 一级代理ip, 二级代理ip...

Although X-Forwarded-For is optional in the process of obtaining the client ip, I personally recommend keeping it so that when a security problem occurs, the source can be traced back according to the log file.

There is a pit:

In addition to the above configuration part, netizens also gave a host header

proxy_set_header Host $host;

First of all, this header is not required, and second, the header host and the host header generated by proxy_pass forwarding will conflict, resulting in interface 502. However, after this configuration is updated, restarting nginx including using nginx -t for testing will not report an error. This is worth paying attention to.

java get

Scenario: When the server receives a client request, it generally needs to perform signature verification, client IP limitation, etc. When performing client IP limitation, it needs to obtain the real IP first. Generally divided into two situations:

Method 1: The client directly accesses the server (nginx, squid, haproxy) without proxy;

Method 2: The client passes through a multi-level proxy and finally reaches the server (nginx, squid, haproxy);

  The client request information is included in the HttpServletRequest, and the client IP can be obtained through the method getRemoteAddr(). At this time, if you are using method 1, you can directly obtain the real IP of the client. And if it is in the form of proxy in method 2, after multi-level reverse proxy at this time, the real IP of the client cannot be obtained through the method getRemoteAddr(), and the forwarded request information can be obtained through x-forwarded-for. When the client request is forwarded, the IP will be appended and separated by commas, for example: 10.47.103.13,4.2.2.2,10.96.112.230.

 Parameters in the request:

request.getHeader("x-forwarded-for") : 10.47.103.13,4.2.2.2,10.96.112.230

request.getHeader("X-Real-IP") : 10.47.103.13

request.getRemoteAddr():10.96.112.230

After the client access is forwarded, the IP will be appended and separated by commas. The final and accurate client information is:

  • If x-forwarded-for is not empty, it is the first IP before the comma;
  • If X-Real-IP is not empty, it is the IP;
  • otherwise getRemoteAddr();

Code example:

 
 

  At this time, under normal circumstances, the real IP of the client can be obtained. It should be noted that for the form of load on the server side, it is necessary to configure and save x-forwarded-for. The current load forms include haproxy, nginx and other forms. The structure diagram is as follows:

 /** 
     * 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址, 
     * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值 
     *  
     * @return ip
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for"); 
        System.out.println("x-forwarded-for ip: " + ip);
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {  
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if( ip.indexOf(",")!=-1 ){
                ip = ip.split(",")[0];
            }
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("Proxy-Client-IP");  
            System.out.println("Proxy-Client-IP ip: " + ip);
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("WL-Proxy-Client-IP");  
            System.out.println("WL-Proxy-Client-IP ip: " + ip);
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("HTTP_CLIENT_IP");  
            System.out.println("HTTP_CLIENT_IP ip: " + ip);
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");  
            System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("X-Real-IP");  
            System.out.println("X-Real-IP ip: " + ip);
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getRemoteAddr();  
            System.out.println("getRemoteAddr ip: " + ip);
        } 
        System.out.println("获取客户端ip: " + ip);
        return ip;  
    }

Guess you like

Origin blog.csdn.net/u010919402/article/details/130075954