How to get the server request IP

In:
Cha Cha brother
Jetty / Tomcat + Nginx reverse proxy to obtain client real IP, domain name, protocol, port

X-Forwarded-For use fake IP flaw causes the client and Prevention

1. IP address problem

The client's request after a reverse proxy server Nginx, RemoteAddr address is the address of Nginx.

After Nginx reverse proxy, Servlet application by request.getRemoteAddr()taking the IP is the IP address of Nginx, not the real client IP, by request.getRequestURL()domain name acquisition, protocol, port access Nginx is a Web application domain, protocol, port, not the customer real domain name on the client browser address bar, protocol, port.

For example, in a table of the IP server 10.4.64.22, Jetty or tomcat port number 8080, Nginx port number 80, Nginx reverse proxy port 8080.

server {
    listen 80;
    location / {
        proxy_pass http://127.0.0.1:8080; # 反向代理应用服务器HTTP地址
    }
}

In a browser on another machine open http://10.4.64.22/test access to a Servlet application, obtain client IP and URL:

System.out.println("RemoteAddr: " + request.getRemoteAddr());
System.out.println("URL: " + request.getRequestURL().toString());

The results are:

RemoteAddr: 127.0.0.1
URL: http://127.0.0.1:8080/test

Can be found, Servlet program to get the client IP is an IP Nginx instead of the machine where the browser IP, acquired URL is the URL address Nginx proxy_pass configuration consisting of, rather than a real address on the browser address. If Nginx as a reverse proxy server backend https http service, request.getRequestURL()obtain the URL is http prefix, rather than https prefix. Unable to get into the real address in the browser address bar.
If at this time to request.getRequestURL()get used to the stitching URL Redirect address, there will be a jump to the wrong address, which is a recurring problem Nginx reverse proxy.

2. Causes of problems

Nginx reverse proxy is actually a bridge between the client and the client real application server (usually a browser) to access Nginx server, Nginx go to access the Web server. For Web applications, the HTTP client requests Nginx is not the real client browser, if not special treatment, then, will Nginx Web application as requested by the client, to obtain client information is Nginx Information.

3. Solution

It can be solved by the following two aspects:

  1. Since Nginx proxy server, all client requests are forwarded from Nginx to Jetty / Tomcat, Nginx need to configure some HTTPHeader to give this information to agents Jetty / Tomcat.

  2. Jetty / Tomcat this end (server) Nginx HTTP Header passed from obtaining client information.

Add the following configuration:

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

In the above configuration is Nginx reverse proxy, you attach some requests Header.

  1. Host: contains the client's real domain name and port number.
  2. X-Forwarded-Proto: indicates that the client real protocol (http or https).
  3. X-Real-IP: Indicates that clients true IP
  4. X-Forwarded-For: The Header and X-Real-IP is similar, but it will include real IP client and the middle of each proxy server in the multi-layer proxy.

Output in the try request.getRemoteAddr () and request.getRequestURL () of.

RemoteAddr: 127.0.0.1
URL: http://10.4.64.22/test
  1. RemoteAddr retrieved address or Nginx address instead of the real client IP.
  2. The browser address bar is https prefix, but request.getRequestURL () to get the URL or http prefix. Nginx configuration is just not completely solve the problem.

1. Get X-Forwarded-For or X-Real-IP

 public String getIp(HttpServletRequest request) throws Exception {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null){
            if (!ip.isEmpty() && !"unKnown".equalsIgnoreCase(ip)) {
                int index = ip.indexOf(",");
                if (index != -1) {
                    return ip.substring(0, index);
                } else {
                    return ip;
                }
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (ip != null) {
            if (!ip.isEmpty() && !"unKnown".equalsIgnoreCase(ip)) {
                return ip;
            }
        }
        ip = request.getHeader("Proxy-Client-IP");
        if (ip != null) {
            if (!ip.isEmpty() && !"unKnown".equalsIgnoreCase(ip)) {
                return ip;
            }
        }
        ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip != null) {
            if (!ip.isEmpty() && !"unKnown".equalsIgnoreCase(ip)) {
                return ip;
            }
        }
        ip =  request.getRemoteAddr();
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }

Request header meaning:

  1. X-Forwarded-For:
    only will be added through the HTTP proxy or load balancing (such as Nginx), the format is X-Forwarded-For:client1,proxy1,proxy2, under normal circumstances, the first real client ip IP, back through the proxy server's IP .

  2. Proxy-Client-IP / WL- Proxy -Client-IP
    that is typically after apache http request to the server only, while the agent is generally used together with apache http Proxy-Client-Ip request header, and WL-Proxy-Client-IP his weblogic plugin plus head.

  3. Real-IP-the X-
    nginx proxy will generally add this request headers.

Jetty

Jetty in jetty.xml file server, locate httpConfig, adding configuration:

<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">

    ...

  <Call name="addCustomizer">
    <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
  </Call>
</New>

Restart Jetty, and then open the browser http://10.4.64.22/test test results:

RemoteAddr: 10.1.3.7
URL: http://10.4.64.22/test

At this point can be found in request.getRemoteAddr()the acquired IP is no longer 127.0.0.1, but the real client IP. request.getRequestURL()The URL also get real URL on the browser, if Nginx as https proxy request.getRequestURL()prefix will be https.

Tomcat

And Jetty Similarly, if you use Tomcat as the application server. You can also configure Tomcat server.xml file, and finally join in the Host element:

<Valve className="org.apache.catalina.valves.RemoteIpValve" />

4. X-Forwarded-For forgery

General client (eg a browser) sends HTTP request is not X-Forwarded-Forthe first, when the request reaches the first proxy server, proxy server will add X-Forwarded-Forrequest headers, set the value to IP address of the client (ie, the leftmost first value), followed if there are multiple agents, in turn will be appended to the IP X-Forwarded-Forheader to the right, the final request reaches the Web server, application by taking X-Forwarded-Fortake the first left a real client IP is the IP header.

However, if the client upon initiation request, a request to bring a forged head X-Forwarded-For, since each subsequent additional agents will not be covered, so when the final server, the acquired IP address of the first left the client will be the fake IP. Which is above Java code getClientIp () method to obtain the IP address is likely to be a fake IP address.

Fake X-Forwarded-For header method is very simple, such as Postman you can easily do:

16013479-2e469c8b1ffb221d.png
Postman fake X-Forwarded-For

5. How to prevent

Method One: Configure on the direct external Nginx reverse proxy server

proxy_set_header X-Forwarded-For $remote_addr;

Here the use of $ remote_addr alternative above $ proxy_add_x_forwarded_for. $ Proxy_add_x_forwarded_for IP will be added in the original X-Forwarded-For, which is equivalent to the opportunity to forge the X-Forwarded-For. The $ remote_addr is to obtain a direct TCP connection is the customer end IP (similar to Java in request.getRemoteAddr ()), this is not fake, fake even if the client will be overwritten, not appended.

Note that, if there is a multi-layer proxy, as long as the configuration of X-Forwarded-For as $ remote_addr on Nginx direct foreign visit, Nginx internal layer or to configure $ proxy_add_x_forwarded_for, otherwise Nginx internal layer will overwrite real IP client.

Method Two: traversing the X-Forwarded-For

Realization of ideas: traversal IP address X-Forwarded-For header, and the above process is different, not the left of the first IP direct access, but right to left traversal. Regular expressions can weed out known IP network and IP proxy server itself (for example, beginning with 192.168), the first non-IP will get removed when traversing a trusted client IP. The trick of this method is that the instant fake X-Forwarded-For, then the request arrives at the application server, IP will be forged in the left X-Forwarded-For value, you can avoid traversing right to left to get these forged IP address.

Reproduced in: https: //www.jianshu.com/p/23ce44445e75

Guess you like

Origin blog.csdn.net/weixin_33912638/article/details/91146402