imbolc / axum-client-ip

A client IP address extractor for Axum
MIT License
42 stars 13 forks source link

An SecureClientIP with a priority fallback system #12

Open Power2All opened 1 year ago

Power2All commented 1 year ago

Hi,

Is it possible to have something like: CF Header > XRealIP > ConnectInfo

In this case, looking for the CF Header, and if that doesn't exist, try XRealIP, and if that doesn't exist, take the ConnectInfo IP address of client. Someway to add a priority lane, and if none of it works, giving a 500 error eventually to give up. This would make it easy to host a server behind CloudFlare, but also make it work without CloudFLare.

Thanks !

imbolc commented 1 year ago

Hi :)

Make sure you read the why different extractors section and understand the security implications of this approach.

I believe in your situation it's better to use SecureClientIp instead with a setting e.g. in env vars. So changing hosting wouldn't require any code changes, but still the IP would be spoof-proof.

However, if you're sure, you can just copy the InsecureClientIp implementation and change the extractors order the way you'd like: https://docs.rs/axum-client-ip/latest/src/axum_client_ip/insecure.rs.html#31-55

Power2All commented 1 year ago

Hi,

Thanks for the fast response. The thing is, I run both a API and a Service block system (I work on Torrust-Axum github repository), and some of them work through CloudFlare, but another is firewalled running on a different port. For now I use the approach you explained above with a environment variable, however, I do not see the insecure thing about having a waterfall fallback option. Should just be optional next to the statically fixed extractors, if you know what I mean. If you are unable to implement something like this, I'll have to create a own made wrapper for it though.

[Edit] Wait, you have a waterfall approach already in the InsecureClientIp ? If that's the case, perfect, then I can continue using that with the custom extractor order idea.

imbolc commented 1 year ago

CF Header, and if that doesn't exist, try XRealIP, and if that doesn't exist, take the ConnectInfo IP

Let's say you aren't behind CF, then someone could just add CF header to the request with any IP they want to trick the waterfall approach.

Power2All commented 1 year ago

Yes and no. Just with x forwarded, you can make a whitelist of ip ranges that are allowed to forward. Works for x-forwarded-for but also CF header. Good example is Traefik for docker. You whitelist the IP ranges of Cloudflare (you can google for them), and those only allow the header to be used.

imbolc commented 1 year ago

I don't understand, aren't your trying to get a user ip? If so, how ip ranges of CF could help?

Power2All commented 1 year ago

I don't understand, aren't your trying to get a user ip? If so, how ip ranges of CF could help?

The webserver, if not firewalled to allow only CF to proxy, could receive both with and without CF forwarding requests. If the latter one, it would break the code if using the Secure mode. As for your question how IP ranges help, simple:

X-Forwarded-For RFC states that it should append a IP of the Proxy server, and the Client IP either at the beginning or end of the list. To be sure the proxies forwarding are allowed to do so, there is mostly used a "whitelist" of the IP's (or CIDR range) that are valid to forward. For example, if I connect directly to the web server with CF enabled, would give me a error, but not when I connect through CloudFlare, thus in my opinion it should fallback to the Client IP it's connecting with.

Another example, is that I could have my own VPS servers running a simple NGINX proxy forwarder, but I need to allow the use of X-Forwarded-For for those IP's that run my NGINX proxy. That's when a whitelist comes into play, that hold the IP ranges (handy in CIDR format) that are validated as legitimate sources.

If you still need some info how others use this: https://doc.traefik.io/traefik/v2.1/routing/entrypoints/#forwarded-header This might be a interesting read, I use this as well.