Spec-Zone.ru › Ruby on Rails 4.1

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

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

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

Константы

VALID_IP

Эта константа содержит регулярное выражение, которое валидирует все известные формы IP-адресов версии 4 и 6, с сокращениями или без, адаптированное из этого gist.

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

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

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

calculate_ip() Показать исходный код

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

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

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

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

# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 133
def calculate_ip
  # Set by the Rack web server, this is a single value.
  remote_addr = ips_from('REMOTE_ADDR').last

  # Could be a CSV list and/or repeated headers that were concatenated.
  client_ips    = ips_from('HTTP_CLIENT_IP').reverse
  forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR').reverse

  # +Client-Ip+ and +X-Forwarded-For+ should not, generally, both be set.
  # If they are both set, it means that this request passed through two
  # proxies with incompatible IP header conventions, and there is no way
  # for us to determine which header is the right one after the fact.
  # Since we have no idea, we give up and explode.
  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=#{@env['HTTP_CLIENT_IP'].inspect} " +
      "HTTP_X_FORWARDED_FOR=#{@env['HTTP_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
to_s() Показать исходный код

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

# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 167
def to_s
  @ip ||= calculate_ip
end

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

filter_proxies(ips) Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 180
def filter_proxies(ips)
  ips.reject { |ip| ip =~ @proxies }
end
ips_from(header) Показать исходный код
# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 173
def ips_from(header)
  # Split the comma-separated list into an array of strings
  ips = @env[header] ? @env[header].strip.split(/[,\s]+/) : []
  # Only return IPs that are valid according to the regex
  ips.select{ |ip| ip =~ VALID_IP }
end

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

Spec-Zone.ru

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