Nginx Multilayer Agent Gets Real Client IP

Keywords: Programming Nginx Java

Generally, applications use Nginx as a reverse proxy, and Nginx may be multi-tiered. If you want to get the original client IP address in the internal service. You need to do some configuration.

Outermost Nginx

To prevent forgery of the X-Forwarded-For header, the X-Forwarded-For can be set to the real IP$remote_addr in the outermost Nginx. The $remote_addr is the client IP (similar to request.getRemoteAddr() in Java) that is directly connected to TCP, which cannot be forged, even if the client forgery is overwritten, not appended.

    upstream innerservice {
        server 192.168.12.33:9001;
        server 192.168.12.34:9002;
    }
    server {
        listen    9000;
        server_name  192.168.12.22;
        root         /usr/share/nginx/html;
        include /etc/nginx/default.d/*.conf;
        location / {
            proxy_pass http://innerservice;
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-PORT $remote_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
    }

Follow-up Nginx configuration

    upstream innerservice {
        server 192.168.12.33:9001;
        server 192.168.12.34:9002;
    }
    server {
        listen    9000;
        // xxx
        location / {
            proxy_pass http://innerservice;
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-PORT $remote_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

Getting Real IP in Java

/**
 * Description: Client Information Acquisition Filter
 */
public class ClientContextFilter extends OncePerRequestFilter {

    /**
     * Nginx IP Address Header Added by Default
     */
    public static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For";

    /**
     * Additional IP address headers are invoked between internal microservices
     */
    public static final String HEADER_X_REMOTE_USER_IP = "X-Remote-User-IP";

    /**
     * IP Segmentation symbols of response heads
     */
    private static final String IP_HEADER_DELIMITER = ",";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String remoteUserIP = loadRemoteUserIP(request);
            ClientContext context = new ClientContext();
            context.setClientIP(request.getRemoteAddr());
            context.setRemoteUserIP(remoteUserIP);
            ClientContextHolder.setContext(context);
            filterChain.doFilter(request, response);
        } finally {
            ClientContextHolder.clearContext();
        }
    }

    private String loadRemoteUserIP(HttpServletRequest request) {
        String xForwardedHeader = request.getHeader(HEADER_X_FORWARDED_FOR);
        // First try to get it from X-Forwarded-For
        if (xForwardedHeader != null && xForwardedHeader.trim().length() > 0) {
            String[] ips = xForwardedHeader.split(IP_HEADER_DELIMITER);
            return ips[0].trim();
        } else {
            // Attempt to retrieve from an internal custom header
            String internalIPHeader = request.getHeader(HEADER_X_REMOTE_USER_IP);
            if (null != internalIPHeader && internalIPHeader.trim().length() > 0) {
                return internalIPHeader.trim();
            } else {
                return null;
            }
        }
    }
}

The principle is to define a custom header when the service is passed back, and put the real IP in this header. Background services can take two IP addresses

  • request.getRemoteAddr() - Gets the intranet IP address of the caller service
  • Load RemoteUserIP - Get the Real Client IP Address at the Source

Posted by sonofyoda on Thu, 03 Oct 2019 03:47:31 -0700