A lot of this post, as the title indicates goes into the difficulties in determining the real client-ip in a modern envrionment where reverse proxies are quite common and normal. Pointing out some common issues:
- Headers are untrustworthy. Unless a proxy strips the original value instead of appending to it, an attacker can set the first value in the X-Forwarded-For` (XFF) list to whatever they want, even non-IPs.
- Multiple Headers. The same header may be present multiple times, and according to the HTTP/1.1 spec, if the value of the header is a comma-separated list, it must be possible to combine multiple header fields into one. This can be a problem if you only look at the first instance of a header (as is default in Golang for example using
http.Header.Get(name)), as the IP should have been appended to the last header not the first.
- Private IPs, if using an internal proxy, a privatae IP might end up in the header.
- Inconsistent Splitting, the HTTP/1.1 spec indicates that there can be command-separated lists in headers, but some code may look for a command and a space (
- Unencrypted data is untrustworthy. If you’re not using HTTPS the header may have been tampered with at any point
- Other Headers, like nginx’s
X-Client-IP, or CloudFlare’s
True-Client-IPmight be present and trusted in generic code, but not actually provided by a trusted proxy.
After laying all these issues out (in better detail that I have here) the author goes into how to do the parsing correctly, and then points out several instances of real parsing issues, that may or may not have security implications depending on the applications running behind the improperly implemented proxies/middleware.