在Rails中request.remote_ip和request.ip有什么区别?

正如标题所示,您可以使用这两种方法获取客户端的IP。 我想知道是否有任何分歧。 谢谢。

在源代码中有

“/usr/local/rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_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 

但我真的不知道这个影响

来源:

 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 

Rack :: Request看起来像这样

 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 

所以remote_ip优先于action_dispatch.remote_ip 。 这是由ActionDispatch::RemoteIp中间件设置的。 你可以看到中间件的源代码,它在被调用时检查欺骗攻击,因为它调用GetIp.new来设置envvariables。 这是必要的,因为即使通过本地代理, remote_ip读取IP地址,正如Clowerweb所解释的。

request.ip返回ip,不pipe是本地代理ip地址(localhost地址)还是不是。 request.remote_ip更聪明,并获得本地代理之外的客户端的IP地址。

request.ip

request.ipRack::Request提供的基本IP检测。 它的当前定义可以在https://github.com/rack/rack/blob/master/lib/rack/request.rbfind。;

它遵循的algorithm是首先检查REMOTE_ADDR标头的任何不可信的IP地址,如果它发现任何,它会select一个列出。 在这种情况下,“可信”IP地址是保留私有子网范围内的 IP地址,但请注意,它与正则expression式匹配,这可能不是最好的办法。 如果没有不可信的REMOTE_ADDR则查看HTTP_X_FORWARDED_FOR标头,并选取列出的最后一个不可信的标头。 如果这两个都没有显示任何人,它可能会退回到可能是127.0.0.1的原始REMOTE_ADDR

request.remote_ip

request.remote_ip是由ActionDispatch::Request (inheritance自Rack::Request )提供的增强型IP检测。 这是问题中显示的代码。 正如你所看到的,它回落到request.ip除非action_dispatch.remote_ip被设置在@env 。 这由RemoteIp中间件完成,该中间件包含在默认的Rails堆栈中。 你可以在https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb看到它的源代码。;

RemoteIp中间件如果启用,则提供以下附加function:

  • 提供可选但默认的IP欺骗检测。
  • 允许过滤configuration代理地址,而不仅仅依赖于默认值。
  • 使用IPAddr类来正确testingIP范围,而不是依赖易碎的正则expression式。
  • 使用HTTP_CLIENT_IP作为潜在IP的来源。

该algorithm类似于request.ip但略有不同。 它使用HTTP_X_FORWARDED_FOR从最后到第一,然后HTTP_CLIENT_IP从最后到第一,然后最后是REMOTE_ADDR的最后一个条目。 它把这些全部列入清单并过滤代理,挑选剩下的第一个。

IP欺骗检测

RemoteIp提供的IP欺骗检测function不是特别强大,如果最后一个HTTP_CLIENT_IP不在HTTP_X_FORWARDED_FOR ,它HTTP_CLIENT_IP引发exception。 这不一定是攻击的一个症状,但它可能是错误configuration的一个症状,或者是使用不同惯例的代理组合,这些惯例不会产生一致的结果。

使用哪个

在一个简单的设置中,你的代理都是本地的或私有的子网,你可能会逃避request.ip ,但是request.remote_ip应该被认为是一般的优越select。 如果您正在使用公共互联网路由代理(例如多个CDN),则可以configurationRemoteIp以便为您提供正确的客户端IP,而request.ip只有在您可以让您的上游代理正确设置REMOTE_ADDR

安全configuration

现在就Tim Coulter关于欺骗的评论发表评论。 他绝对是你应该关心的,但是他错了,如果你默认支持nginx或haproxy的话,你可能会被欺骗。 RemoteIp旨在通过select链中的最后一个 IP来防止欺骗。 X-Forwarded-For规范指定每个代理将请求者的IP附加到链的末尾。 通过筛选列入白名单的代理,最后一项保证是您的第一个白名单代理编写的客户端IP。 当然有一个警告,那就是你必须运行一个总是设置/附加X-Forwarded-For ,所以Tim的build议实际上应该是相反的: 运行代理时只能使用request.remote_ip

如何configuration公共IP代理

这一切都很好,但ActionDispatch::RemoteIp已经在默认的中间件堆栈中。 如何重新configuration​​它以添加我的代理CIDR?

添加到你的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