I have originally submitted the issue to spring-cloud-gateway, so pardon the reproducer name.
In RFC for handling Forwarded and X-Forwarded compatibility [1] and there is an issue when X-Forwarded-For contains an IPv6 as first entry. I could reproduce this only via Cloudfare with an ISP that offers dual IP stack.
The X-Forwarded-For header that is received from Cloudfare when source IP is a real IPv6 is shown below (fully anonymized, of course).
Consider the following
Note that IPv6 addresses may not be quoted in
X-Forwarded-For and may not be enclosed by square brackets, but they
are quoted and enclosed in square brackets in "Forwarded".
X-Forwarded-For: 192.0.2.43, 2001:db8:cafe::17
becomes:
Forwarded: for=192.0.2.43, for="[2001:db8:cafe::17]"
When using X-Forwarded-For header such as
X-Forwarded-For: fd00:fefe:1::4, 192.168.0.1
The org.springframework.web.util.ForwardedHeaderUtils
produces an InetHostAddress without square brackets "[]"
When using an equivalent Forwarded
header, the InetHostAddress is present WITH square brackets "[]"
Forwarded: for="[fd00:fefe:1::4]", for=192.168.0.1
It would be nice if both would return the same format.
Reproducer https://github.com/ZIRAKrezovic/gateway-reproducer
Simply run ./mvnw clean verify
Adjust DemoApplicationSimpleTests
to switch between X-Forwarded-For
and Forwarded
as shown above.
[1] https://datatracker.ietf.org/doc/html/rfc7239#section-7.4
Comment From: rstoyanchev
We can add the square brackets in the x-forwarded-for case to match the RFC forwarded header syntax.
Comment From: krezovic
Hi @rstoyanchev - I believe only IPv6 should be enclosed within square brackets. This is true for "Forwarded" handling. If you enclose IPv4 within square brackets then it's again inconsistent.
Comment From: rstoyanchev
Good point. In that case, we might not be able to do this. I'm not sure there is an easy way to tell them apart.
Comment From: krezovic
The obvious difference is that IPv6 blocks are separated by colon :
rather than dot .
Comment From: rstoyanchev
I was thinking of an address with a port, but "X-Forwarded-For" is just a host, so it should be an easy check indeed.
Comment From: ZIRAKrezovic
Even with port, IPv6 will always contain more than one :
, and may even contain two ::
. But you don't need to validate an IPv6 only to detect it