跳到內容 跳到搜尋

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 裝置),或者位於代理伺服器後方而且代理伺服器以不正確或 confusing 的方式設定標題(例如:AWS ELB),是有道理的。

custom_proxies 參數可以接受一個列舉,它會用來取代 TRUSTED_PROXIES。任何代理伺服器設定都會將您要的值置於 X-Forwarded-For 清單的中央(或開頭),而且您的代理伺服器會在其後方。如果您的代理伺服器沒有被移除,請透過 custom_proxies 參數傳遞它們。這樣,中間件就會忽略那些 IP 位址,並傳回您想要的 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