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 位址。如果您在意這一點,那麼您需要在這個中間件執行之前,明確捨棄或忽略這些標題。或者,也可以移除這個中間件,以避免無意間依賴它。
固定值
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 位址。
來源:顯示 | 在 GitHub 上
# 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 位址。
來源:顯示 | 在 GitHub 上
# 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