-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
Restore original remote_ip algorithm. #7980
Conversation
I am 99% sure this is right, the tests were new, so I wasn't sure how to 'revert' them. Please check this request well before merging. ;) |
I put some notes into the extended commit messages, but the upshot is that it works correctly now, it ignores private IPv6 IPs now (which it didn't do before), and the code is much shorter. Yay. :) |
@@ -105,22 +99,15 @@ def to_s | |||
@ip = calculate_ip | |||
end | |||
|
|||
private | |||
private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opps. Take care to not change the code conventions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my defense, he changed my outdented protected
to an indented private
. :) I'll restore it to what it was before the commit I am reverting here.
I did some comments inline. The feature seems fine but we need to remove the comment tests (if they are not needed) or uncomment they (if they are needed) |
Oops! Fixing, thank you. On Oct 17, 2012, at 6:30 PM, Rafael Mendonça França [email protected] wrote:
|
I'm not sure that this is right to use last address from header Here is the usage of mod_extract_forwarded for apache for example: Sorry, I have problems with accessing github.com right now, so I comment On Thu, Oct 18, 2012 at 9:41 AM, André Arko [email protected]:
|
Ohhh, I understand what the problem is now. Many proxies don't actually modify the X-Forwarded-For header. Instead, they add another X-Forwarded-For header. According to the HTTP spec, that means that the values should be concatenated, joined by a comma. If you're using a ruby server that understands repeated headers, the correct IP will then be the last value. If the proxy conforms to the W3C spec that you linked, the correct IP will be the first value. Um. How can we resolve this? FWIW, I've only ever seen the "adds a second header" proxy type in the wild (I know HAProxy does this). |
In addition, other blog posts I have read on the subject seem to indicate that the last IP is the correct one in real-world scenarios. |
And indeed, the Apache bug on this subject also seems to imply we should be using the last IP address in the concatenated list. |
I did my pull last time because I used this functionality on groupon On Thu, Oct 18, 2012 at 10:45 AM, André Arko [email protected]:
|
It seems like an option on the middleware is the way to go if this is a common need, and a replacement middleware that removes the calls to |
Ugh. |
@steveklabnik inorite? 😭 |
I don't like the idea to add Yet Another Configuration Option, but I don't know if this is not common |
I always prefer what is correct to what is not. It's not our job to fix bugs in other projects, we should follow the spec. Then again, I don't have anything currently deployed in production that depends on this in either direction ;) |
If it helps at all, this pull does fix at least one bug in the trusted proxies regex, and also restores the same behaviour as e.g. Apache. I personally think that's the way it should work, but hey. I'm biased. :) On Oct 20, 2012, at 12:00 PM, Steve Klabnik [email protected] wrote:
|
Figured I'd weigh in here. I use Google Page Speed Service in front of Heroku. Not the craziest, most unheard of Rails environment. There, the client's IP is the FIRST in the X-Forwarded-For csv. Can we make this configurable? |
I guess the upside is that it's always going to be first or last? Unless you combine Google Page Speed and HAProxy, then it'll be in the middle. -_- I'm ready to implement an option that lets you tell the middleware whether you want the first or last IP. I'm not sure which option should be the default, though, since the "spec correct" one is first and the "works like Apache etc" one is last. :| |
I think that default should be last IP (your implementation), because long time nobody noticed that, and my pull was opened about 8 months before merged in. So I think first IP is like exception. I can help you with implementation |
Makes sense to me. Thanks for offering to help! I imagine @steveklabnik can get you hooked up with push to his repo so you can add to this pull request if you have some patches. On Oct 22, 2012, at 8:39 AM, Alexey Gaziev [email protected] wrote:
|
Yes, @gazay let me know if you have some commits and I can give you access to my repo. |
Great, thanks guys! |
So, I'm ready to push some commits. I did the same option usage as with ip_spoofing_check. And I wrote some tests to check different order usage And btw I think that we shouldn't filter values from X_FORWARDED_FOR and give to user unexpected IP of unknown proxy server. We should give him only first or last ip from list as we decided here. I changed code in remote_ip.rb and fix tests for it. What do you think @indirect, @steveklabnik? |
You're added to my repo. |
I've added commits. I'm not sure about name of option - x_forwarded_for_last_ip, but that's all I could think of |
I think the ability to pass in proxies to be filtered is very important, because its the only way to get the real IP in a situation where one proxy adds to the front but another proxy adds to the end. So I think we should keep it. Since the option is already scoped to the remote IP middleware, and applies to more than one header, I would suggest naming it "first_ip" or "first_client_ip". On Oct 22, 2012, at 11:09 AM, Alexey Gaziev [email protected] wrote:
|
And of course when I just suggested "first_ip", I actually meant "last_ip". :P On Oct 22, 2012, at 11:33 AM, Alexey Gaziev [email protected] wrote:
|
About filtering – I see the problem, you right, I'll change it back. About naming - last_ip or last_client_ip not really clear when someone will read this code or try to change option. It's like if ip_spoofing_check will be just ip_check - not sure what this option allow to check. Maybe last_forwardable_ip? |
Ahh, I see. I was thinking the option should apply to REMOTE_ADDR too, but it seems that that header will only ever have a list of IPs due to duplicated headers, and so reverse is always the correct direction. How about calling the option "last_forwarded_ip"? That includes both the important part of the header name, and literally describes what you will get if you turn the option on -- the last IP from the proxy's list of forwarded IPs. |
@gingerlime ahh, you make a very good point. I didn't connect the dots during the earlier discussion, but the option shouldn't be needed at all if you can explicitly list the proxies whose addresses you don't want to count. @gazay, would that work in your situation? Given the potential for IP spoofing vulnerabilities, I think we might want to ultimately revert to the original behaviour without an option, and suggest in the comments/docs that anyone who needs something custom should remove this middleware and insert their own instead. |
Yes, while we read from X-Forwarded-For in the implementation of remote_ip then you'll always be potentially vulnerable to spoofing attacks. I'd suggest just adding something like: request.forwarded_ips # => ['x.x.x.x', 'y.y.y.y', 'z.z.z.z'] Then the config just becomes a question of first or last from that method. FWIW, if you're using remote_ip in a security setting you're completely crazy ;) |
The config in question is pretty much exactly that (mod some filtering of obviously not useful IPs). So that seems okay, I guess. On Nov 18, 2012, at 12:35 PM, Michael Koziarski [email protected] wrote:
|
@NZKoz I just re-read your comment:
This is not entirely accurate. If you trust your proxy server(s), and by trust I also mean you trust them to handle If you don't use any (trusted) proxy servers, then you should simply ignore the |
So: what exactly needs to be done to move this forward? |
...better...docs? |
I've thought about this some more, and I'd like to propose a different final solution: how about we remove the first/last IP option, revert to the (safe) last IP, and beef up the docs explaining how to use the trusted proxy option to remove IPs from the end until what's left is the IP that you're interested in? On Nov 28, 2012, at 2:01 PM, Steve Klabnik [email protected] wrote:
|
I can see that too. @NZKoz what do you think? |
sounds good to me |
Great. I'll try to get that implemented today. |
Ping! @indirect did you get a chance to play with this? |
Oh man. Totally fell off my list. Today or tomorrow, I hope. |
No worries bro, know you've been busy. |
I agree with reverting to last IP and documenting the trusted proxy option. What I would like to see is an option to ignore
|
That seems reasonable to me. On Dec 24, 2012, at 11:46 AM, John Firebaugh [email protected] wrote:
|
@jfirebaugh after editing this, I'm not sure why you want to be able to monkeypatch this at all. You can completely resolve your stated use-case by adding a middleware farther out that strips the "garbage" header, and then disable the spoof checking using the option that is provided. I personally would like to remove the spoof checking, because AFAIK there aren't any proxies that set both Client-Ip and X-Forwarded-For, but I'm sure that's a totally separate PR and discussion. :) |
Figuring out the correct IP is the responsibility of the RemoteIp middleware, right? Folks shouldn't have to write a second middleware that deals in the same protocol details as RemoteIp in order to get RemoteIp to work correctly in what is a very common environment. I'm all for removing the spoof checking as well, but I think there needs to be a configuration option to say which of Client-Ip and X-Forwarded-For is accurate. |
The job of this middleware is to return the IP address reported in the headers of the request. IMO, if you want to ignore one of those headers, then yes, you should have to write code that deletes that header. Have you asked the Amazon guys about fixing their headers so that code isn't needed? On Jan 1, 2013, at 5:16 PM, John Firebaugh [email protected] wrote:
|
Okay. I have coded and documented the fuck out of this thing. /cc @steveklabnik |
needs rebase |
@rafaelfranca bro, I just rebased this 4 minutes ago. It needs another one?! |
Proxy servers add X-Forwarded-For headers, resulting in a list of IPs. We remove trusted IP values, and then take the last given value, assuming that it is the most likely to be the correct, unfaked value. See [1] for a very thorough discussion of why that is the best option we have at the moment. [1]: http://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/ Fixes rails#7979
Huh, stupid CHANGELOG. :P Rebased! Again! QUICK SOMEBODY PUSH THE MERGE BUTTON |
Restore original remote_ip algorithm.
🤘 Thanks guys. ❤️ |
o_O |
We incorrectly were using the first address, rather than the last one.
Fixes #7979
/cc @indirect @gazay