在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.ip
是Rack::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