What is the difference between request.remote_ip and request.ip in Rails?

As the header says, you can get a client ip with both methods. I wonder if there are any differences. Thank.

in the source code goes

"/ USR / local / RVM / gems / ruby-1.9.3-P194 / gems / actionpack-3.2.3 / Library / stock _dispatch / http / request.rb" 257L, 8741C

def ip @ip ||= super end # Originating IP address, usually set by the RemoteIp middleware. def remote_ip @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s end 

but I really don't know the consequences.

+48
ruby ruby-on-rails rack
Jun 12 2018-12-12T00:
source share
3 answers

From source:

 module ActionDispatch class Request < Rack::Request # ... def ip @ip ||= super end def remote_ip @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s end # ... end end 

where Rack :: Request looks like this

 module Rack class Request def ip remote_addrs = split_ip_addresses(@env['REMOTE_ADDR']) remote_addrs = reject_trusted_ip_addresses(remote_addrs) return remote_addrs.first if remote_addrs.any? forwarded_ips = split_ip_addresses(@env['HTTP_X_FORWARDED_FOR']) if client_ip = @env['HTTP_CLIENT_IP'] # If forwarded_ips doesn't include the client_ip, it might be an # ip spoofing attempt, so we ignore HTTP_CLIENT_IP return client_ip if forwarded_ips.include?(client_ip) end return reject_trusted_ip_addresses(forwarded_ips).last || @env["REMOTE_ADDR"] end end end 

So, remote_ip takes priority action_dispatch.remote_ip . This is installed by the ActionDispatch::RemoteIp . You can see in this middleware source that it checks for spoofing attacks on invocation, as it calls GetIp.new to set this env variable. This is necessary because remote_ip reads the ip address even through local proxies, as explained by Clowerweb.

+32
Jun 12 2018-12-12T00:
source share

request.ip returns ip whether it is the local ip proxy address (localhost address) or not. request.remote_ip smarter and gets the client IP address outside of local proxies.

+62
Jun 12 '12 at 12:56
source share

request.ip

request.ip is the basic ip discovery provided by Rack::Request out of the box. Its current definition can be found at https://github.com/rack/rack/blob/master/lib/rack/request.rb .

The next algorithm is to check the REMOTE_ADDR header for any untrusted IP addresses, and if it finds one, it selects the first one . The "trusted" IP addresses in this case are IP addresses from reserved ranges of private subnets , but note that this matches the regular expression, which is probably not the best way to do this. If there is no unreliable REMOTE_ADDR , then it looks at the HTTP_X_FORWARDED_FOR header and selects the last unreliable. If none of them shows to anyone, it returns to raw REMOTE_ADDR , which is probably 127.0.0.1.

request.remote_ip

request.remote_ip is the improved IP discovery provided by ActionDispatch::Request (which inherits from Rack::Request ). This is the code indicated in the question. As you can see, it returns to request.ip if action_dispatch.remote_ip not set to @env . This is done using the RemoteIp , which is included on the Rails stack by default. You can see its source at https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb .

The RemoteIp , if enabled, provides the following additional functions:

  • Provides optional but standard IP spoofing detection.
  • Allows you to filter the configuration proxy addresses instead of relying only on the default values.
  • Uses the IPAddr class to actually test IP ranges, rather than relying on a fragile regex.
  • Uses HTTP_CLIENT_IP as a source of potential IP addresses.

The algorithm is similar to request.ip , but slightly different. It uses HTTP_X_FORWARDED_FOR from the last to the first, then HTTP_CLIENT_IP from the last to the first, and then finally the last record of REMOTE_ADDR . It puts everything in the list and filters the proxy, choosing the first remaining one.

IP Spoofing Detection

The IP spoofing detection provided by RemoteIp is not particularly powerful, all it does is throw an exception if the last HTTP_CLIENT_IP not in HTTP_X_FORWARDED_FOR . This is not necessarily a sign of an attack, but it is probably a symptom of an incorrect configuration or combination of proxies using different conventions that do not lead to a consistent result.

What to use

In a simple installation where your proxies are local or on private subnets, you can probably leave with request.ip , but request.remote_ip should be considered the best choice overall. If you use proxies with public Internet routing (for example, many CDNs), then RemoteIp can be configured to give you the correct client IP addresses out of the box, whereas request.ip will only be correct if you can set your proxy server up REMOTE_ADDR correct.

Secure configuration

Now turn to Tim Coulter's comment on spoofing. He is definitely right, you should be worried, but he is wrong that you can be faked if by default you are behind nginx or haproxy. RemoteIp designed to prevent spoofing by selecting the last IP address in the chain. The X-Forwarded-For specification indicates that each proxy attaches the requester’s IP address to the end of the chain. By filtering whitelisted proxies, the last record guarantees the client IP address written by your first whitelisted proxy. Of course, there is one caveat that you really should run a proxy server that always installs / adds X-Forwarded-For , so Tim’s advice should actually be the opposite: use request.remote_ip only when proxy.

How to configure for public IP protocols

This is all fine and good, but ActionDispatch::RemoteIp already on the middleware stack by default. How to reconfigure it to add a CIDR proxy server ?!

Add this to your application.rb :

 check_spoofing = true proxies = ["23.235.32.0/20", "203.57.145.0/24"] proxies += ActionDispatch::RemoteIp::TRUSTED_PROXIES config.middleware.swap ActionDispatch::RemoteIp, ActionDispatch::RemoteIp, true, proxies 
+11
Mar 25 '17 at 8:37
source share



All Articles