Spec-Zone.ru › Ruby on Rails 5.0

класс ActionDispatch::RemoteIp::GetIp

Родитель:
Объект

Класс GetIp существует как способ отложить обработку данных запроса в фактический IP-адрес. Если вызывается метод ActionDispatch::Request#remote_ip, этот класс рассчитает значение и затем поместит его в кэш.

Публичные методы класса

new(req, check_ip, proxies) Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 86
def initialize(req, check_ip, proxies)
  @req      = req
  @check_ip = check_ip
  @proxies  = proxies
end

Публичные методы экземпляра

calculate_ip() Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 110
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, remote_addr].flatten.compact

  # If every single IP option is in the trusted list, just return REMOTE_ADDR
  filter_proxies(ips).first || remote_addr
end

Просматривает различные заголовки IP-адресов, чтобы найти IP-адрес, наиболее вероятно являющийся адресом фактического удалённого клиента, делающего этот запрос.

REMOTE_ADDR будет верным, если запрос отправляется непосредственно в процесс Ruby, например, на Heroku. Когда запрос проходит через прокси-сервер, такой как HAProxy или NGINX, IP-адрес, который сделал исходный запрос, помещается в заголовок X-Forwarded-For. Если прокси-серверов несколько, этот заголовок может содержать список IP-адресов. Другие прокси-сервисы устанавливают заголовок Client-Ip, поэтому мы проверяем и его.

Как обсуждалось в этой записи о уязвимостях подделки IP-адресов в Rails, хотя первый IP в списке, скорее всего, является «исходным» IP, его также мог задать клиент злонамеренно.

Для определения первого адреса, который (вероятно) точный, мы берём список IP-адресов, удаляем известные и доверенные прокси, а затем берём последний оставшийся адрес, который, предположительно, был задан одним из этих прокси.

to_s() Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 152
def to_s
  @ip ||= calculate_ip
end

Запоминает значение, возвращаемое методом calculate_ip, и возвращает его для использования ActionDispatch::Request.

Защищённые методы экземпляра

filter_proxies(ips) Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 174
def filter_proxies(ips)
  ips.reject do |ip|
    @proxies.any? { |proxy| proxy === ip }
  end
end
ips_from(header) Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 158
def ips_from(header)
  return [] unless header
  # Split the comma-separated list into an array of strings
  ips = header.strip.split(/[,\s]+/)
  ips.select do |ip|
    begin
      # 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
  end
end

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API