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

时间:2012-06-12 12:49:35

标签: ruby-on-rails ruby rack

随着标题的出现,您可以使用这两种方法获取客户端的IP。我想知道是否有任何差异。谢谢。

在源代码中

“的/ usr /本地/ RVM /宝石/红宝石1.9.3-P194 /宝石/ ActionPack的-3.2.3 / LIB /动作 _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

但我真的不知道其含义。

3 个答案:

答案 0 :(得分:73)

request.ip返回客户端ip,即使该客户端是代理。

request.remote_ip更聪明,并获得实际的客户ip。只有在沿途的所有代理设置X-Forwarded-For标题时才能执行此操作。

答案 1 :(得分:36)

来自消息来源:

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来设置该env变量。正如Clowerweb所解释的那样,即使通过本地代理,remote_ip也会读取IP地址,这是必需的。

答案 2 :(得分:32)

request.ip

request.ip是开箱即用的Rack::Request提供的基本ip检测。它的当前定义可以在https://github.com/rack/rack/blob/master/lib/rack/request.rb找到。

它遵循的算法是首先检查REMOTE_ADDR标头中是否存在任何不受信任的IP地址,如果找到任何IP地址,则会选择列出的第一个。在这种情况下,“可信”IP地址是来自reserved private subnet ranges的IP地址,但请注意它与正则表达式匹配,这可能不是最好的方法。如果没有不受信任REMOTE_ADDR,则会查看HTTP_X_FORWARDED_FOR标题,然后选择列出的最后不受信任的标题。如果这些都没有显示任何人,则它会回落到原始REMOTE_ADDR,这可能是127.0.0.1。

request.remote_ip

request.remote_ip是由ActionDispatch::Request(继承自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中间件,则会提供以下附加功能:

  • 提供可选但默认的IP欺骗检测。
  • 允许过滤配置代理地址,而不是仅依赖默认值。
  • 使用IPAddr类来正确测试IP范围,而不是依赖脆弱的正则表达式。
  • 使用HTTP_CLIENT_IP作为潜在IP的来源。

该算法与request.ip类似,但略有不同。它从最后到第一个使用HTTP_X_FORWARDED_FOR,然后从最后到第一个使用HTTP_CLIENT_IP,最后使用REMOTE_ADDR的最后一个条目。它将所有这些放在一个列表中并过滤代理,选择第一个剩余的。

IP欺骗检测

RemoteIp提供的IP欺骗检测并不是特别强大,如果最后HTTP_CLIENT_IP不在HTTP_X_FORWARDED_FOR中,它会引发异常。这不一定是攻击的症状,但它可能是使用不同约定的错误配置或代理混合的症状,这些约定不会产生连贯的结果。

使用哪种

在一个简单的设置中,您的代理服务器都是本地或私有子网,您可能可以使用request.ip,但request.remote_ip应该被认为是一般的优越选择。如果您使用具有公共互联网路由的代理(例如许多CDN),则可以配置RemoteIp以提供开箱即用的正确客户端IP,而request.ip只有在您获得上游代理正确设置REMOTE_ADDR

安全配置

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

如何配置公共IP代理

这一切都很好,但ActionDispatch::RemoteIp已经在默认的中间件堆栈中。如何重新配置​​它以添加我的代理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