Closed jwoertink closed 2 years ago
Instead of being an array, should it just be the single string value for the header? It would make sense that once you figure out which header is being passed back, it'll always be that same one. I've ran in to an issue where the LB config has changed, but I guess in that case, you'd just update the app to use a different header and do a new deploy.
@jwoertink I think that makes sense. Should this be an opt-in feature as well?
@robacarp which part are you thinking for the opt-in?
The remote_address
has been in Lucky for a few versions now, and it's always used the X_FORWARED_FOR
header. So that would stay as the default, but just give you the option to change it. The only new bit would be the remote_ip
which would just be an extra property on request.
My preference would be to have the whole thing be opt-in, but I understand why that might not be a desirable change to make. There are a bunch of ways an incorrectly configured x-forwarded-for system can be abused, and having a web server which reads the header without the proxy server in front of it is one of them.
I spent some time poking at what Rack does for this. A notable difference is that it doesn't return just one value, but an array of values. They take the added precaution of filtering out a default list of IP ranges, too. There's a lot more code in this rack module than I expected.
Ah, ok. I see what you're saying. In that case, we'd need to remove this
Then we could add docs on adding it in if you need. I would eventually like to make it more robust like they do with the Rack stuff. IPSpoofing checks and all that...
Got sent this article: https://adam-p.ca/blog/2022/03/x-forwarded-for/
One interesting thing is we currently have this line: https://github.com/luckyframework/lucky/blob/4cb2108f3e05acaadc6c948a07b2838154e8871a/src/lucky/remote_ip_handler.cr#L21
which uses the first (left most) IP, but according to this article, we should be using the last (right most)
When deriving the “real client IP address” from the X-Forwarded-For header, use the rightmost IP in the list.
It also mentions to use the last instances of the header, which I think Crystal is doing..
make sure to use the last instance of that header.
I think maybe we can include a link to this article in the comments. We make the default X-Forwarded-For
, with the option to change it, but it's really up to you to figure out how to setup your reverse proxy and/or load balancer to pass back what you need. Then this will just handle the 80% use case.
Purpose
Fixes #1643
Description
If you need access to the client's IP address, using
remote_address
can be troublesome since it casts toSocket::Address
, and not allSocket::Address
subclasses contain anaddress
method. So you usually end up with some code like this:But now you can just do
In addition, I've also added a new habitat config option
ip_header_names
option. This allows you to configure the header names of where the client IP may come from. e.g.X-Real-Ip
,Forwarded-For
, etc...Checklist
crystal tool format spec src
./script/setup
./script/test