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

Min*_*Pan 68 ruby rack ruby-on-rails

正如标题所示,您可以使用这两种方法获取客户端的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
Run Code Online (Sandbox Code Playgroud)

但我真的不知道其含义.

Clo*_*web 77

request.ipip即使该客户端是代理,也返回客户端.

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


shi*_*ime 39

来自:

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
Run Code Online (Sandbox Code Playgroud)

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 
Run Code Online (Sandbox Code Playgroud)

因此remote_ip优先考虑action_dispatch.remote_ip.这是由ActionDispatch::RemoteIp中间件设定的.您可以在该中间件的源代码中看到它在被调用时正在检查欺骗攻击,因为它正在调用GetIp.new以设置该env变量.这是必要的,因为remote_ip甚至通过本地代理读取IP地址,Clowerweb解释.

  • 根据我的经验,即使`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`将生成一个6.66.6.66的`request.remote_ip`,这将欺骗你所拥有的任何ip检查轨. (10认同)

gtd*_*gtd 38

request.ip

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

其遵循的算法是首先检查REMOTE_ADDR标头是否存在任何不受信任的IP地址,如果找到任何IP地址,则选择列出的一个IP地址.在这种情况下,"可信"IP地址是来自保留的私有子网范围的 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欺骗检测

所提供的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
Run Code Online (Sandbox Code Playgroud)