-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
go-chi/chi/middleware/RealIP and go-chi/httprate suffer from problems getting the "real" client IP. I'll try to break it down into categories.
RealIP isn't necessarily "security-related", but it depends on how the dev uses it. I would argue that rate limiting -- and so httprate -- is security-related.
For a full explanation of the problems mentioned here, please see my blog post about it. (Here's the chi-specific section, but all the rest is informative.)
Headers are untrustworthy, unless added by a reverse proxy you control
The RealIP middleware has this comment:
You should only use this middleware if you can trust the headers passed to you (in particular, the two [three, actually] headers this middleware uses), for example because you have placed a reverse proxy like HAProxy or nginx in front of Chi. If your reverse proxies are configured to pass along arbitrary header values from the client, or if you use this middleware without a reverse proxy, malicious clients will be able to make you very sad (or, depending on how you're using RemoteAddr, vulnerable to an attack of some sort).
This is a good warning, but a) there's no such warning on chi's httprate.KeyByIP (even though it does the same thing), and b) it's not a comprehensive enough warning.
Some reverse proxies, like AWS ALB, lets all header values through that it doesn't set itself. So it will let through True-Client-IP
and X-Real-IP
. An attacker can spoof either of those headers, and that will end up as the IP that is reported by RealIP or the IP that's gets rate-limited by httprate.
X-Forwarded-For
is tricky
Leftmost vs Rightmost
Also, X-Forwarded-For
is only appended to by reverse proxies, so the only IPs in it that are trustworthy are the ones that were added by reverse proxies that you control. httprate, however, takes the first IP in XFF. So an attacker can trivially spoof it. The leftmost XFF IP should never be used for security-related purposes.
Switching to rightmost will introduce an XFF multiple-headers problem
Go's http.Header.Get
returns the first instance of a header, but to get the rightmost IP from XFF, you need to get the last. (More info here.)
Leftmost values can be garbage
If you really want to use the leftmost IP, you need to be aware that it could be either a private-space IP address or complete garbage.
A suggested algorithm for how to get it is here.
Parsing the XFF IP list
httprate splits the XFF list by comma-space rather than just comma. RFC 2616 only says "comma-separated" for list headers. (And RealIP splits by comma. And I've seen reverse proxies append without a space. And I've looked at about ten other projects and haven't seen another example of splitting by comma-space.)
Results
RealIP can easily be made to return a spoofed header.
httprate can be bypassed by spoofing different IPs. Possibly the server memory can be exhausted by spoofing very large fake IP values.