New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for configuring trusted_proxies XFF depth #5804
Comments
Thanks; yeah we can probably expand on it. A new Would you be willing to contribute a PR to implement it?
Sigh. Why don't they have a "replace" mode that ignores all incoming XFF and just sets it to the remote addr? That's so silly. FWIW Cloudflare also does it incorrectly by default but it is possible to fix using their "rules". Explained here https://www.authelia.com/integration/proxies/fowarded-headers/#cloudflare |
Yes, the AWS ALB approach is both odd and correct. Odd, because AWS CloudFront and all major reverse proxies do indeed provide a "wipe all incoming values, inject appropriate client IP". And correct because reverse proxies are meant to append in that direction, so you can have guarantees the right-most IP in XFF is the safest one. It seems like a huge oversight on AWS' part that they did not include this option in AWS ALB. I've flagged this to them in a Slack channel. Waiting to hear back. I've never programmed in Go before but happy to take a stab at it. I saw @mholt post that your focus is on adding test coverage throughout the codebase. Spent the last little bit learning how to write tests, so I'll continue down that direction. A draft PR is open here: #5805 I believe this commit accurately describes the issue best. b0028d1 This should be a failing test – the only failing test I've written – which breaks backwards compatibility and highlights the potential security bug in a left-most approach. Take a look at the test + inline comment I've left:
I'd like to propose introducing a backwards-compatible switch to trusted_proxy config. Instead of specifying depth, the user can instead opt-in to a right-most trusted proxy scan. This functionality will, from right to left, find the first untrusted IP in the XFF stack and use that as the client IP. This follows both MDN's and adam-p's recommendations. The other option is to break backwards compat and opt everyone into the right-most... but that seems annoying, even if it is the safe thing to do. Thoughts @francislavoie @mholt ? I'll avoid moving much further until hearing back. It's my first time writing Go, and I don't want to commit too much time writing non-idiomatic code or tests if I'm way off track here. Let me know. |
I made an attempt at introducing a new flag. The changes related to the flag can be seen in this commit. The previous tests in the PR all still pass. I think this should maintain backwards compatibility for anyone who wants to keep their existing client_ip behaviour. Let me know your thoughts on approach and naming. |
This is mostly done in #5805, I think the only remaining piece is to support an optional |
This relates to #5104
Firstly, wonderful software that really makes great default decisions. Thanks for caddy.
I suggest adding a configuration parameter to
trusted_proxies
which would allow deciding the depth at which the Client IP is in theX-Forwarded-For
(referred to as XFF in this issue) stack of IPs. This is a feature request but also a bug/security issue. Currently, it is very easy to misusetrusted_proxies
due to how XFF handling is implemented in caddy.In the original PR, it is noted:
Taking the left-most value is actually the least trustworthy value in nearly all cases. Wikipedia entry re: XFF:
And since adam-p published his article on XFF, MDN has since updated their documentation as well to reflect the security risk in trusting the left-most IP address (thanks to a PR from adam-p).
Recommendation
There are two ways to manage XFF headers safely. The first is by specifying the depth at which your caddy reverse proxy exists (trusted proxy count), and the second is finding the first right-most IP address that isn't in your trusted proxy list (trust proxy list).
Currently caddy pulls the left-most valid IP address. This is not how most reverse proxies work with the header. There is only 1 reverse proxy I know of that behaves very incorrectly, which is Microsoft's IIS. It inserts previous hops to the right of the header instead of the left, which would make finding the left-most the appropriate approach. Instead, caddy should apply the same logic but find the right-most untrusted address. This would be the second Trusted proxy list approach, described above.
However to maintain backwards compatibility, you can also consider adding the Trusted proxy count option. This is as simple as defining a number that specifies how from from the right is the client IP address in the XFF header.
e.g. a header value of
X-Forwarded-For: <spoofed address>, <client address>, <proxy 1 address>, <proxy 2 address>
, we would usexff_depth 3
to pull the realclient_ip
address out and ignore the spoofed address.Right now, the implementation of
trusted_proxies
means caddy can never safely extract the client IP while behind an AWS Application Load Balancer. See this documentation from AWS on how values are forwarded.The text was updated successfully, but these errors were encountered: