I've had problems with this though. I want to get the ip4 address from cloudflare, instead of ip6 and it's next to impossible AFAICT. (for the free plan anyway)
In fact if the user has IPv6, IP blocks/Rate limits wont affect the other users on the CGNAT legacy address.
I have multiple websites on Cloudflare and can receive IPv4 addresses just fine, though for Cloudflare fronted websites it's usually better to use the CF-Connecting-IP as people can send any value in the X-Forwarded-For header.
Maybe some intermediate layer turns the IPv4 into a IPv6-mapped IPv4 address?
[1] https://werkzeug.palletsprojects.com/en/stable/middleware/pr...
I implemented those recommendations in Caddy to enable a "trusted proxies" system which informs the proxy, logging, request matching etc to safely use the client IP taken from proxy headers.
For example it reminds that standards & intermediaries you trust might still allow multiple unconcatenated XFF headers though and the XFF unpeel by right to left heuristic fails if you only look at the e.g. the first such header.
This reminded me that there always seems to be a past or future pitfall case lurking, such as using old code/library honoring a X-HTTP-Method-Override header (e.g. historically used to ~convert POST to PUT bypassing client CORS restrictions).
Many holes I've noticed over the years seem to spring from legacy preservation of well intended endruns of restrictions, for example I can presently in Safari exploit a bug to get a crypto digest calculated for me within an insecure context ... I find this quite usefully locally (e.g. lan http: , data: , ~bookmarklets that I control) but nonetheless I reported the bug and am trying not to rely on it.
Two things it failed to advise for defense are:
(1) I can simply just reject requests that provide multiple keys of this header. In Go, I will use `http.Header.Values(headerName)` to check the count. There is no good reason for having multiple keys of it. Any misconfiguration in setting them is the client's problem.
(2) I can and I must reject large requests that have too many header bytes. In Go, when initializing `http.Server`, I can give it the `MaxHeaderBytes` argument. Sending megabytes of headers stops here.
If I understood correctly, when wanting the rightmost-ish XFF value, I can use the rightmost value that is not in a list of trusted subnets, assuming there is at least one remaining value left of it.
I'm sure plenty of lbs/reverse proxies and app servers don't set things, establish trust, or filter the header properly though, because, people, but it is easy to lock down.
Oops :)
It is one of these trust-based headers that need to be cleared at the edge of your network / trust zone.
2. If the connecting party (real TCP connection remote end) is in the trusted list, then take the rightmost address in XFF and set as remote end.
3. Repeat 2 until you get an address not in the trusted list.
4. That is now the real client IP. Discard anything to the left of it in XFF. (though maybe log it, if you want)
The article seems to forget the step of checking the real TCP connection remote address (from my skimming), which means that if the web server can be accessed directly, and not just through a load balancer that always sets the header, then the article is a security hole.
> The article seems to forget the step of checking the real TCP connection remote address (from my skimming)
as this alerted me when reading the article to see their very important, but not highlighted, caveat emptor that covers this dangerous case :
Note that this logic assumes that your server is not directly accessible.
If it is, you need to check the actual request source IP address is one of yours first -
effectively treating that as an extra right-most address.
Eventually I added some runtime checks that log a warning and linked to documentation for both of those issues and a few other common ones.
My support burden has decreased dramatically since then.
The funniest is when the app renders user IP addresses somewhere and you can get XSS through it.
Moreover, the Forwarded header has all the security pitfalls of the XFF header.
westurner•3d ago
> Dropping all external values like this is the safest approach when you're not sure how secure and reliable the rest of your call chain is going to be. If other proxies and backend apps are likely to blindly trust the incoming information, or generally make insecure choices (which we'll get into more later) then it's probably safest to completely replace the X-Forwarded-For header at that outside-world facing reverse proxy, and ditch any untrustworthy data in the process.
X-Forwarded-For: https://en.wikipedia.org/wiki/X-Forwarded-For :
> Just logging the X-Forwarded-For field is not always enough as the last proxy IP address in a chain is not contained within the X-Forwarded-For field, it is in the actual IP header. A web server should log both the request's source IP address and the X-Forwarded-For field information for completeness
HTTP header injection: https://en.wikipedia.org/wiki/HTTP_header_injection
This OWASP page has a list of X-Forwarded-For and X-FORWARDED-foR and similar headers; "Headers for IP Spoofing" https://owasp.org/www-community/pages/attacks/ip_spoofing_vi...
A sufficient WAF should detect all such attempts.
The X-Forwarded-For Wikipedia article mentions that RFC 7239 actually standardizes the header and parsing:
RFC 7239: "Forwarded HTTP Extension" (2014): https://www.rfc-editor.org/rfc/rfc7239