跳至内容 跳至搜索

Action Dispatch RemoteIp

此中间件计算发出请求的远程客户端的 IP 地址。它通过检查可能包含地址的各种标头来实现,然后选择不在受信任 IP 列表中的最后一个设置地址。这遵循了例如 Tomcat 服务器 的先例。关于算法的更详细解释,请参见 GetIp#calculate_ip

一些 Rack 服务器会连接重复的标头,例如 HTTP RFC 2616 所要求的。一些 Rack 服务器只是丢弃前面的标头,只报告 最后一个标头中给出的值。如果您位于多个代理服务器后面(例如 NGINX 到 HAProxy 到 Unicorn),那么您应该测试您的 Rack 服务器以确保您的数据是好的。

如果您不使用代理,这会导致您容易受到 IP 欺骗攻击。此中间件假设至少有一个代理在周围设置了包含客户端远程 IP 地址的标头。如果您不使用代理,因为您托管在例如 Heroku 上,没有 SSL,任何客户端都可以通过设置 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 ].map { |proxy| IPAddr.new(proxy) }
 

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

属性

[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 地址,并返回您想要的那个。

# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 65
    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 93
def call(env)
  req = ActionDispatch::Request.new env
  req.remote_ip = GetIp.new(req, check_ip, proxies)
  @app.call(req.env)
end