Retrieve the remote client IP address of the incoming request in spring cloud gateway
search cancel

Retrieve the remote client IP address of the incoming request in spring cloud gateway

book

Article ID: 399200

calendar_today

Updated On:

Products

VMware Tanzu Application Service

Issue/Introduction

The X-Forwarded-For header is intended to be used by proxies in your networking chain to track the IP address of the client from where the call originated. When a web request is made, the server receiving the request is aware of the IP address that is calling it. When using the X-Forwarded-For
header, the receiving server should append the calling client’s IP address to the list of IP addresses in that header value. The resulting header might look something like this: 'X-Forwarded-For: <client>, <proxy1>, <proxy2>'.

However, retrieving the client IP address from X-Forwarded-For header in Spring Boot 3 is considered unsafe. This approach is vulnerable to spoofing, as a malicious client could set an initial value for the X-Forwarded-For which would be accepted by the resolver.

Resolution

Spring Cloud Gateway’s XForwardedRemoteAddressResolver has two static constructor methods to extract a trusted IP.

  • XForwardedRemoteAddressResolver::trustAll
  • XForwardedRemoteAddressResolver::maxTrustedIndex

XForwardedRemoteAddressResolver::trustAll returns a RemoteAddressResolver that always takes the first IP address found in the X-Forwarded-For header. We shall avoid this option and pick up the second.

XForwardedRemoteAddressResolver::maxTrustedIndex takes an index that correlates to the number of trusted infrastructure running in front of Spring Cloud Gateway. If Spring Cloud Gateway is, for example only accessible through HAProxy, then a value of 1 should be used. If two hops of trusted infrastructure are required before Spring Cloud Gateway is accessible, then a value of 2 should be used.

In a spring cloud gateway app, we can use either GlobalFilter (Affects All Routes) or GatewayFilter(Per-Route Customization) to retrieve the client IP address for the purpose of modifying or validating the request before forwarding it.

Here is an example of GlobalFilter (Affects All Routes).

@Configuration
public class GatewayConfig {

        @Bean
        public GlobalFilter customClientIpFilter() {
                return (exchange, chain) -> {
                        String clientIp = getClientIp(exchange);
                        System.out.println("Client IP: " + clientIp);
                        return chain.filter(exchange);
                };
        }

        private String getClientIp(ServerWebExchange exchange) {
                XForwardedRemoteAddressResolver resolver = XForwardedRemoteAddressResolver.maxTrustedIndex(1);
                InetSocketAddress remoteAddress = resolver.resolve(exchange);
                return (remoteAddress != null) ? remoteAddress.getAddress().getHostAddress() : "Unknown";
        }

       @Bean
        public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
                return builder.routes()
                                .route(r -> r.host("127.0.0.1")
                                                .and()
                                                .path("/example")
                                                .uri("http://www.example.com"))
                                .build();
        }

}

Additional Information