spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

No X-Forwarded-For (RemoteIP) header is written due to incompatibility between XForwardedHeadersFilter and ForwardedHeadersTransformer

Open stefanocke opened this issue 2 years ago • 6 comments

Describe the bug If ForwardedHeaderTransformer is enabled in Spring Cloud Gateway, X-Forwarded-For Header will not be sent to upstream services

Steps to reproduce

  • Enable ForwardedHeaderTransformer in Spring Cloud Gateway by setting: server.forward-headers-strategy=framework
  • Setup some upstream service to which the gateway fowards requests.
  • Use a REST client to send some request to the upstream service via gateway. Set the X-Forwarded-For header in the request.
  • Watch the request going to the upstream service. It has no X-Forwarded-For header.
  • Other headers, like X-Forwarded-Host will work.

Debugging

Since a while, ForwardedHeaderTransformer in Spring Boot supports X-Forwarded-For header:

remoteAddress = UriComponentsBuilder.parseForwardedFor(request, remoteAddress);

In UriComponentsBuilder.parseForwardedFor, the address is build as following:

return InetSocketAddress.createUnresolved(host, port);

However, in Spring Cloud Gateway, we have the following in XForwardedHeadersFilter:

if (isForEnabled() && request.getRemoteAddress() != null
				&& request.getRemoteAddress().getAddress() != null) {
			String remoteAddr = request.getRemoteAddress().getAddress().getHostAddress();
			write(updated, X_FORWARDED_FOR_HEADER, remoteAddr, isForAppend());
		}

Debugging shows, that request.getRemoteAddress().getAddress() is null and so, no X-Fowarded-For Header is written. I guess that is due to the InetSocketAddress.createUnresolved in UriComponentsBuilder.

I don't know whether ForwardedHeaderTransformer / UriComponentsBuilder or XForwardedHeadersFilter is wrong here, but together, they fail.

P.S.: createUnresolved seems to be intentionally, to avoid DNS resolution. See https://github.com/spring-projects/spring-framework/commit/c5ac8e8ab62cf7a616d5316bc6ef6d5d5e461c10 So, it would probably be the best solution if XForwardedHeadersFilter could (also) deal with an unresolved remote address.

stefanocke avatar Jun 22 '22 14:06 stefanocke

Is there any solution to this?

justwiebe avatar Apr 12 '23 16:04 justwiebe

Is there a work around for this?

hamish-spireon avatar Oct 20 '23 01:10 hamish-spireon

oh, gold, please I have this question too

blacklee123 avatar Dec 28 '23 12:12 blacklee123

request.getRemoteAddress().getAddress() cannot be null in the current implementation since this line in XForwardedHeadersFilter

String remoteAddr = request.getRemoteAddress().getAddress().getHostAddress();

would throw an NPE. Since, as I understand, no DNS resolution is by design, we could replace that line with

InetAddress address = request.getRemoteAddress().getAddress();
String remoteAddr = (address == null) ? /* some default value; an empty string? */ : address.getHostAddress();

What that default value may be depends on whether there are any expectations of that value (e.g. if a specific format is expected, if it's in any way parsed at any place)

@spencergibb does this train of thought relate to you? If so, will an empty string do?

NadChel avatar Mar 22 '24 09:03 NadChel