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


75

随着标题的发展,您可以使用两种方法获取客户端的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

但我真的不知道其中的含义。

Answers:


43

来自来源:

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来设置环境变量,因此它在被调用时正在检查欺骗攻击。remote_ip正如Clowerweb解释的那样,这是必需的,因为甚至可以通过本地代理读取IP地址。


11
以我的经验,即使request.remote_ip通过HTTP_X_FORWARDED_FOR链进行查找,但如果在Nginx或haproxy后面有Rails,它仍然可以被欺骗。在nginx中,使用proxy_set_header X-Forwarded-For $remote_addr;代替proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;。在后一种情况下,curl -H "X-Forwarded-For: 6.66.6.66" http://example.com将产生request.remote_ip6.66.6.66,这将欺骗您在Rails中使用的所有IP检查。
Tim Coulter

84

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

request.remote_ip更聪明,得到了真正的客户ip。仅当所有代理都设置X-Forwarded-For标头时,才能完成此操作。


56

request.ip

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

遵循的算法是首先检查REMOTE_ADDR标头中是否存在任何不受信任的IP地址,如果找到了该IP地址,它将选择列出的一个。在这种情况下,“受信任的” IP地址是来自保留的专用子网范围的IP地址,但请注意,它通过regex进行匹配,这可能不是最佳方法。如果没有不信任的内容,REMOTE_ADDR那么它将查看HTTP_X_FORWARDED_FOR标题,并选择列出的最后一个不信任的内容。如果这些都不显示任何内容,那么它会退回到原始REMOTE_ADDR值(可能是127.0.0.1)。

request.remote_ip

request.remote_ip是的增强IP检测ActionDispatch::Request(由继承Rack::Request)。这是问题中显示的代码。如您所见,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欺骗检测

所提供的IP欺骗检测RemoteIp是不是特别强大,它的作用是抛出一个异常,如果最后HTTP_CLIENT_IP不是HTTP_X_FORWARDED_FOR。这不一定是攻击的征兆,但可能是配置错误或使用不同约定混合代理的征兆,这些约定没有产生连贯的结果。

使用哪个

在代理都位于本地或专用子网中的简单设置中,您可能可以摆脱request.ip,但request.remote_ip通常应将其视为首选。如果将代理与公共Internet路由(例如许多CDN)一起使用,则RemoteIp可以配置为为您提供开箱即用的正确客户端IP,而request.ip只有在您可以REMOTE_ADDR正确设置上游代理的情况下才是正确的。

安全配置

现在来解决蒂姆·库尔特关于欺骗的评论。他绝对是对​​的,应该引起您的关注,但是他错了,如果默认情况下您落后于nginx或haproxy,那么您可能会被欺骗。 RemoteIp通过选择链中的最后一个IP来防止欺骗。在X -转发,对于规范规定,各代理追加请求方的IP到链的末端。通过过滤掉列入白名单的代理,可以确保最后一个条目是您的第一个列入白名单的代理编写的客户端IP。当然还有一点需要说明,这是你必须确实运行一个代理,一直套/追加X-Forwarded-For,所以蒂姆的建议实际上应该是相反的:只有使用request.remote_ip时您正在运行的代理。

如何配置公共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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.