GetIp
类作为一种方法存在,用于延迟将请求数据处理成实际的 IP 地址。如果调用 ActionDispatch::Request#remote_ip
方法,此类将计算该值,然后将其记忆化。
- C
- F
- I
- N
- T
类公共方法
new(req, check_ip, proxies) 链接
源代码:显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 99 def initialize(req, check_ip, proxies) @req = req @check_ip = check_ip @proxies = proxies end
实例公共方法
calculate_ip() 链接
对各种 IP 地址头进行排序,寻找最有可能作为发出此请求的实际远程客户端的地址的 IP。
如果请求直接针对 Ruby 进程(例如在 Heroku 上)发出,REMOTE_ADDR 将是正确的。当请求由 HAProxy 或 NGINX 等其他服务器代理时,发出原始请求的 IP 地址将被放入 X-Forwarded-For
头中。如果有多个代理,该头可能包含 IP 列表。其他代理服务会设置 Client-Ip
头,因此我们也会检查该头。
如 这篇有关 Rails IP 欺骗的文章 中所述,虽然列表中的第一个 IP 可能是“原始”IP,但它也可能被恶意客户端设置。
为了找到第一个(可能)准确的地址,我们获取 IP 列表,移除已知且受信任的代理,然后获取剩下的最后一个地址,该地址可能是由其中一个代理设置的。
源代码:显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 123 def calculate_ip # Set by the Rack web server, this is a single value. remote_addr = ips_from(@req.remote_addr).last # Could be a CSV list and/or repeated headers that were concatenated. client_ips = ips_from(@req.client_ip).reverse! forwarded_ips = ips_from(@req.x_forwarded_for).reverse! # +Client-Ip+ and +X-Forwarded-For+ should not, generally, both be set. # If they are both set, it means that either: # # 1) This request passed through two proxies with incompatible IP header # conventions. # 2) The client passed one of +Client-Ip+ or +X-Forwarded-For+ # (whichever the proxy servers weren't using) themselves. # # Either way, there is no way for us to determine which header is the # right one after the fact. Since we have no idea, if we are concerned # about IP spoofing we need to give up and explode. (If you're not # concerned about IP spoofing you can turn the +ip_spoofing_check+ # option off.) should_check_ip = @check_ip && client_ips.last && forwarded_ips.last if should_check_ip && !forwarded_ips.include?(client_ips.last) # We don't know which came from the proxy, and which from the user raise IpSpoofAttackError, "IP spoofing attack?! " \ "HTTP_CLIENT_IP=#{@req.client_ip.inspect} " \ "HTTP_X_FORWARDED_FOR=#{@req.x_forwarded_for.inspect}" end # We assume these things about the IP headers: # # - X-Forwarded-For will be a list of IPs, one per proxy, or blank # - Client-Ip is propagated from the outermost proxy, or is blank # - REMOTE_ADDR will be the IP that made the request to Rack ips = forwarded_ips + client_ips ips.compact! # If every single IP option is in the trusted list, return the IP # that's furthest away filter_proxies(ips + [remote_addr]).first || ips.last || remote_addr end
to_s() 链接
记忆化 calculate_ip
返回的值,并将其返回给 ActionDispatch::Request
使用。
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 167 def to_s @ip ||= calculate_ip end
实例私有方法
filter_proxies(ips) 链接
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 187 def filter_proxies(ips) # :doc: ips.reject do |ip| @proxies.any? { |proxy| proxy === ip } end end
ips_from(header) 链接
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 172 def ips_from(header) # :doc: return [] unless header # Split the comma-separated list into an array of strings. ips = header.strip.split(/[,\s]+/) ips.select! do |ip| # Only return IPs that are valid according to the IPAddr#new method. range = IPAddr.new(ip).to_range # We want to make sure nobody is sneaking a netmask in. range.begin == range.end rescue ArgumentError nil end ips end