跳至内容 跳至搜索

Action Dispatch RemoteIp

此中间件用于计算发出请求的远程客户端的 IP 地址。它通过检查可能包含该地址的各种头部,然后选择不在受信任 IP 列表中的最后一个设置的地址来完成此操作。这遵循了 e.g. Tomcat 服务器设定的先例。算法的更详细解释可在 GetIp#calculate_ip 中找到。

一些 Rack 服务器会连接重复的头部,如 HTTP RFC 2616 所要求。一些 Rack 服务器则会简单地删除前面的头部,只报告 最后一个头部提供的值。如果您位于多个代理服务器(如 NGINX 到 HAProxy 到 Unicorn)后面,您应该测试您的 Rack 服务器以确保数据是正确的。

如果您不使用代理,这会使您容易受到 IP 欺骗的攻击。此中间件假定至少有一个代理服务器存在并设置了包含客户端远程 IP 地址的头部。如果您不使用代理,例如因为您在没有 SSL 的 Heroku 上托管,那么任何客户端都可以通过设置 X-Forwarded-For 头部来声称拥有任何 IP 地址。如果您对此很在意,那么您需要在此中间件运行之前的某个时候显式删除或忽略这些头部。或者,删除此中间件以避免无意中依赖它。

命名空间
方法
C
N

常量

TRUSTED_PROXIES = [ "127.0.0.0/8", # localhost IPv4 范围,根据 RFC-3330 "::1", # localhost IPv6 "fc00::/7", # 私有 IPv6 范围 fc00::/7 "10.0.0.0/8", # 私有 IPv4 范围 10.x.x.x "172.16.0.0/12", # 私有 IPv4 范围 172.16.0.0 .. 172.31.255.255 "192.168.0.0/16", # 私有 IPv4 范围 192.168.x.x "169.254.0.0/16", # 链路本地 IPv4 范围 169.254.x.x "fe80::/10", # 链路本地 IPv6 范围 fe80::/10 ].map { |proxy| IPAddr.new(proxy) }
 

默认的受信任 IP 列表仅包含 IP 规范保证为私有地址的 IP 地址。这些在生产环境中不会是最终客户端 IP,因此会被丢弃。有关详细信息,请参阅 en.wikipedia.org/wiki/Private_network

Attributes

[R] check_ip
[R] proxies

类公共方法

new(app, ip_spoofing_check = true, custom_proxies = nil)

创建一个新的 RemoteIp 中间件实例。

ip_spoofing_check 选项默认开启。开启时,如果客户端试图谎报自己的 IP 地址,将抛出异常。在面向非 IP 客户端(如 WAP 设备)的网站上,或在设置头部不正确或混乱的代理(如 AWS ELB)后面,关闭此检查是有意义的。

custom_proxies 参数可以接受一个可枚举对象,该对象将用于替代 TRUSTED_PROXIES。任何代理设置都会将您想要的值放在 X-Forwarded-For 列表的中间(或开头),之后是您的代理服务器。如果您的代理未被移除,请通过 custom_proxies 参数传递它们。这样,中间件将忽略这些 IP 地址,并返回您想要的 IP 地址。

# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 67
    def initialize(app, ip_spoofing_check = true, custom_proxies = nil)
      @app = app
      @check_ip = ip_spoofing_check
      @proxies = if custom_proxies.blank?
        TRUSTED_PROXIES
      elsif custom_proxies.respond_to?(:any?)
        custom_proxies
      else
        raise(ArgumentError, <<~EOM)
          Setting config.action_dispatch.trusted_proxies to a single value isn't
          supported. Please set this to an enumerable instead. For
          example, instead of:

          config.action_dispatch.trusted_proxies = IPAddr.new("10.0.0.0/8")

          Wrap the value in an Array:

          config.action_dispatch.trusted_proxies = [IPAddr.new("10.0.0.0/8")]

          Note that passing an enumerable will *replace* the default set of trusted proxies.
        EOM
      end
    end

实例公共方法

call(env)

由于 IP 地址可能不需要,我们将对象存储在此处而不计算 IP,以避免减慢大多数请求的速度。对于那些确实需要知道 IP 的请求,GetIp#calculate_ip 方法将计算并缓存客户端 IP 地址。

# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 95
def call(env)
  req = ActionDispatch::Request.new env
  req.remote_ip = GetIp.new(req, check_ip, proxies)
  @app.call(req.env)
end