Ruby-on-rails Rails 中的 request.remote_ip 和 request.ip 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10997005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the difference between request.remote_ip and request.ip in Rails?
提问by Minqi Pan
As the title goes, you can get the client's ip with both methods. I wonder if there is any differences. Thank you.
正如标题所说,您可以使用这两种方法获取客户端的 ip。我想知道是否有任何差异。谢谢你。
in the source code there goes
在源代码中有
"/usr/local/rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action _dispatch/http/request.rb" 257L, 8741C
"/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
but I really don't know the implications.
但我真的不知道其中的含义。
采纳答案by shime
From source:
从来源:
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
where Rack::Request looks like this
其中 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
So remote_ipgives precedence to action_dispatch.remote_ip. That is being set by ActionDispatch::RemoteIpmiddleware. You can see in that middleware's source that it's checking for spoofing attacks when being called, since it's calling GetIp.newto set that env variable. That's needed since remote_ipreads the ip address even through the local proxies, as Clowerweb explains.
所以remote_ip优先考虑action_dispatch.remote_ip. 这是由ActionDispatch::RemoteIp中间件设置的。您可以在该中间件的源代码中看到它在被调用时正在检查欺骗攻击,因为它正在调用GetIp.new以设置该 env 变量。remote_ip正如 Clowerweb 解释的那样,这是必需的,因为即使通过本地代理也能读取 IP 地址。
回答by Clowerweb
request.ipreturns the client ipeven if that client is a proxy.
request.ipip即使该客户端是代理,也会返回该客户端。
request.remote_ipis smarter and gets the actual client ip. This can only be done if the all the proxies along the way set the X-Forwarded-Forheader.
request.remote_ip更聪明并获得实际客户ip。这只能在沿途的所有代理设置X-Forwarded-For标头时完成。
回答by gtd
request.ip
请求文件
request.ipis the basic ip detection provided by Rack::Requestout of the box. Its current definition can be found at https://github.com/rack/rack/blob/master/lib/rack/request.rb.
request.ip是Rack::Request开箱即用提供的基本 ip 检测。它的当前定义可以在https://github.com/rack/rack/blob/master/lib/rack/request.rb找到。
The algorithm it follows is to first check the REMOTE_ADDRheader for any untrusted IP addresses, and if it finds any, it chooses the firstone listed. "Trusted" IP addresses in this case are IP addresses from the reserved private subnet ranges, but note that it matches by regex which is probably not the best way to do it. If there is no untrusted REMOTE_ADDRthen it looks at the HTTP_X_FORWARDED_FORheader, and picks the lastuntrusted one listed. If neither of those reveals anyone it falls back to the raw REMOTE_ADDRwhich is probably 127.0.0.1.
它遵循的算法是首先检查REMOTE_ADDR头中是否有任何不受信任的 IP 地址,如果找到,则选择列出的第一个。在这种情况下,“受信任的”IP 地址是来自保留私有子网范围的IP 地址,但请注意,它通过正则表达式匹配,这可能不是最好的方法。如果没有不受信任的,REMOTE_ADDR则它查看HTTP_X_FORWARDED_FOR标头,并选择列出的最后一个不受信任的。如果这两个都没有显示任何人,则它会回退到REMOTE_ADDR可能是 127.0.0.1的原始值。
request.remote_ip
request.remote_ip
request.remote_ipis enhanced IP detection provided by ActionDispatch::Request(which inherits from Rack::Request). This is the code shown in the question. As you can see, it falls back to request.ipunless action_dispatch.remote_ipis set on the @env. That is done by the RemoteIpmiddleware, which is included in the default Rails stack. You can see its source at https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb.
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查看其来源。
The RemoteIpmiddleware if enabled provides these additional features:
该RemoteIp如果启用中间件提供这些附加功能:
- Provides optional but default IP spoofing detection.
- Allows configuration proxy addresses to be filtered instead of relying only on defaults.
- Uses the
IPAddrclass to actually test IP ranges properly instead of relying on a brittle regex. - Uses
HTTP_CLIENT_IPas a source of potential IPs.
- 提供可选但默认的 IP 欺骗检测。
- 允许过滤配置代理地址,而不是仅依赖于默认值。
- 使用
IPAddr该类来正确测试 IP 范围,而不是依赖脆弱的正则表达式。 - 用途
HTTP_CLIENT_IP作为潜在的IP地址的来源。
The algorithm is similar to request.ipbut slightly different. It uses HTTP_X_FORWARDED_FORfrom last to first, then HTTP_CLIENT_IPfrom last to first, then finally the last entry of REMOTE_ADDR. It puts those all in a list and filters proxies, picking the first remaining one.
该算法类似于request.ip但略有不同。它使用HTTP_X_FORWARDED_FOR从最后到第一,然后HTTP_CLIENT_IP从最后到第一,最后是最后一个条目REMOTE_ADDR。它将所有这些都放在一个列表中并过滤代理,选择第一个剩余的代理。
IP Spoofing Detection
IP欺骗检测
The IP spoofing detection provided by RemoteIpis not particularly powerful, all it does is raise an exception if the last HTTP_CLIENT_IPis not in HTTP_X_FORWARDED_FOR. This isn't necessarily a symptom of an attack, but it is probably a symptom of a misconfiguration or a mix of proxies using different conventions which are not producing a coherent result.
提供的 IP 欺骗检测RemoteIp并不是特别强大,它所做的只是在最后一个HTTP_CLIENT_IP不在HTTP_X_FORWARDED_FOR. 这不一定是攻击的征兆,但它可能是错误配置或使用不同约定的代理混合的征兆,但不会产生一致的结果。
Which to Use
使用哪个
In a simple setup where your proxies are all local or on private subnets, you can probably get away with request.ip, but request.remote_ipshould be considered the superior choice in general. If you are using proxies with public internet routing (such as many CDNs) then RemoteIpcan be configured to give you correct client IPs out of the box, whereas request.ipwill only be correct if you can get your upstream proxy to set REMOTE_ADDRcorrectly.
在您的代理全部位于本地或私有子网上的简单设置中,您可能可以逃脱request.ip,但request.remote_ip通常应被视为最佳选择。如果您使用具有公共 Internet 路由的代理(例如许多 CDN),则RemoteIp可以配置为开箱即用地为您提供正确的客户端 IP,而request.ip只有在您可以REMOTE_ADDR正确设置上游代理时才正确。
Secure Configuration
安全配置
Now to address Tim Coulter's comment about spoofing. He's definitely right you should be concerned, but he's wrong that you can be spoofed if you're behind nginx or haproxy by default. RemoteIpis designed to prevent spoofing by choosing the lastIP in the chain. The X-Forwarded-Forspec specifies that each proxy append the requester's IP to the end of the chain. By filtering out whitelisted proxies, the last entry is guaranteed to be the client IP written by your first whitelisted proxy. There is one caveat of course, which is that you must actually be running a proxy that always sets/appends X-Forwarded-For, so Tim's advice should actually be opposite: only use request.remote_ipwhen you arerunning a proxy.
现在来解决 Tim Coulter 关于欺骗的评论。他绝对是对的,你应该担心,但他错了,如果你默认支持 nginx 或 haproxy,你可能会被欺骗。 RemoteIp旨在通过选择链中的最后一个IP来防止欺骗。在X -转发,对于规范规定,各代理追加请求方的IP到链的末端。通过过滤掉列入白名单的代理,最后一个条目保证是您的第一个列入白名单的代理写入的客户端 IP。当然还有一点需要说明,这是你必须确实运行一个代理,一直套/追加X-Forwarded-For,所以蒂姆的建议实际上应该是相反的:只有使用request.remote_ip时您正在运行的代理。
How To Configure for Public IP Proxies
如何配置公共 IP 代理
That's all fine and good, but ActionDispatch::RemoteIpis already in the default middleware stack. How do reconfigure it to add my proxy CIDRs?!
这一切都很好,但ActionDispatch::RemoteIp已经在默认的中间件堆栈中。如何重新配置它以添加我的代理 CIDR?!
Add this to your application.rb:
将此添加到您的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

