存在 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 103 def initialize(req, check_ip, proxies) @req = req @check_ip = check_ip @proxies = proxies end
公開類別方法
calculate_ip() 連結
透過各種 IP 位址標頭進行排序,尋找最可能會是發出這個請求的實際遠端客戶端的 IP。
如果請求是以 Heroku 等方法直接向 Ruby 程序發出,REMOTE_ADDR 會正確無誤。當請求是透過 HAProxy 或 NGINX 等其他伺服器代理時,發出原始請求的 IP 位址會放在 X-Forwarded-For
標頭。如果有多個代理,那個標頭可能會包含多個 IP。其他代理服務會設定 Client-Ip
標頭,因此我們也會檢查它。
如同在 這篇關於 Rails IP 偽造的文章 中所討論,名單中的第一個 IP 很可能是「來源」IP,但也可能已被客戶端惡意設定。
為了找到第一個可能是準確的 IP,我們會從 IP 清單中,移除已知且信任的代理,然後取得剩下的最後一個 IP 位址,而該 IP 位址可能是由其中一個代理設定的。
來源: 顯示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 127 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 171 def to_s @ip ||= calculate_ip end
非公開類別方法
filter_proxies(ips) 連結
來源: 顯示 | 在 GitHub 上
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 191 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 176 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