publicar potenciales para leads gratis formulario descargar crear clientes ruby ruby-on-rails-3 logging nginx reverse-proxy

ruby - potenciales - facebook crm integration



Cómo registrar la IP de cliente real en el registro de rieles cuando está detrás de un proxy como nginx (5)

Problema

Tengo una instalación de carriles 3.2.15 con rack 1.4.5 en dos servidores. El primer servidor es un proxy nginx que sirve activos estáticos. El segundo servidor es un unicornio que sirve la aplicación Rails.

En Rails production.log siempre veo la dirección IP nginx (10.0.10.150) y no la dirección IP de mi cliente (10.0.10.62):

Started GET "/" for 10.0.10.150 at 2013-11-21 13:51:05 +0000

Quiero tener la IP del cliente real en los registros.

Nuestra configuración

Los encabezados HTTP X-Forwarded-For y X-Real-IP están configurados correctamente en nginx y he definido 10.0.10.62 como una dirección proxy de confianza al establecer config.action_dispatch.trusted_proxies = /^127/.0/.0/.1$/ en config/environments/production.rb , gracias a otra answer . Puedo verificar que esté funcionando porque los registro en el controlador de la aplicación:

en la app/controllers/application_controller.rb :

class ApplicationController < ActionController::Base before_filter :log_ips def log_ips logger.info("request.ip = #{request.ip} and request.remote_ip = #{request.remote_ip}") end end

en production.log :

request.ip = 10.0.10.150 and request.remote_ip = 10.0.10.62

Investigación

Al investigar, vi que Rails::Rack::Logger es responsable de registrar la dirección IP:

def started_request_message(request) ''Started %s "%s" for %s at %s'' % [ request.request_method, request.filtered_path, request.ip, Time.now.to_default_s ] end

request es una instancia de ActionDispatch::Request . Hereda Rack::Request que define cómo se calcula la dirección IP:

def trusted_proxy?(ip) ip =~ /^127/.0/.0/.1$|^(10|172/.(1[6-9]|2[0-9]|30|31)|192/.168)/.|^::1$|^fd[0-9a-f]{2}:.+|^localhost$/i end def ip remote_addrs = @env[''REMOTE_ADDR''] ? @env[''REMOTE_ADDR''].split(/[,/s]+/) : [] remote_addrs.reject! { |addr| trusted_proxy?(addr) } return remote_addrs.first if remote_addrs.any? forwarded_ips = @env[''HTTP_X_FORWARDED_FOR''] ? @env[''HTTP_X_FORWARDED_FOR''].strip.split(/[,/s]+/) : [] if client_ip = @env[''HTTP_CLIENT_IP''] # If forwarded_ips doesn''t include the client_ip, it might be an # ip spoofing attempt, so we ignore HTTP_CLIENT_IP return client_ip if forwarded_ips.include?(client_ip) end return forwarded_ips.reject { |ip| trusted_proxy?(ip) }.last || @env["REMOTE_ADDR"] end

La dirección IP reenviada se filtra con trusted_proxy? . Debido a que nuestro servidor nginx está utilizando una dirección IP pública y no una dirección IP privada, Rack::Request#ip cree que no es un proxy, sino la verdadera IP del cliente que intenta hacer un spoofing de IP. Es por eso que veo la dirección IP de nginx en mis registros.

En extractos de registro, el cliente y los servidores tienen la dirección IP 10.0.10.x porque estoy usando máquinas virtuales para reproducir nuestro entorno de producción.

Nuestra solución actual

Para eludir este comportamiento, escribí un pequeño middleware de Rack ubicado en app / middleware / remote_ip_logger.rb:

class RemoteIpLogger def initialize(app) @app = app end def call(env) remote_ip = env["action_dispatch.remote_ip"] Rails.logger.info "Remote IP: #{remote_ip}" if remote_ip @app.call(env) end end

Y lo inserto justo después del middleware ActionDispatch::RemoteIp

config.middleware.insert_after ActionDispatch::RemoteIp, "RemoteIpLogger"

De esta manera puedo ver la IP del cliente real en los registros:

Started GET "/" for 10.0.10.150 at 2013-11-21 13:59:06 +0000 Remote IP: 10.0.10.62

Me siento un poco incómodo con esta solución. nginx + unicorn es una configuración común para la aplicación de rieles. Si tengo que registrar la IP del cliente yo mismo, significa que he perdido algo. ¿Es porque el servidor Nginx está usando una dirección IP pública cuando se comunica con el servidor de rieles? ¿Hay alguna manera de personalizar el trusted_proxy? método de Rack::Request ?

EDITADO : agregue la configuración nginx y una captura de solicitud HTTP

/etc/nginx/sites-enabled/site.example.com.conf :

server { server_name site.example.com; listen 80; location ^~ /assets/ { root /home/deployer/site/shared; expires 30d; } location / { root /home/deployer/site/current/public; try_files $uri @proxy; } location @proxy { access_log /var/log/nginx/site.access.log combined_proxy; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_redirect off; proxy_read_timeout 300; proxy_pass http://rails.example.com:8080; } }

El servidor Nginx es 10.0.10.150 . El servidor Rails es 10.0.10.190 . Mi máquina es 10.0.10.62 Al hacer curl http://10.0.10.150/ desde mi máquina, un tcpdump port 8080 -i eth0 -Aq -s 0 en el servidor de rieles muestra estos encabezados HTTP de solicitud:

GET / HTTP/1.0 X-Forwarded-For: 10.0.10.62 X-Forwarded-Proto: http Host: 10.0.10.150 Connection: close User-Agent: curl/7.29.0 Accept: */*

Y los rieles registran /home/deployer/site/current/log/production.log (líneas IP remotas y request.ip que se agregan mediante código personalizado):

Started GET "/" for 10.0.10.150 at 2013-11-22 08:01:17 +0000 Remote IP: 10.0.10.62 Processing by Devise::RegistrationsController#new as */* request.ip = 10.0.10.150 and request.remote_ip = 10.0.10.62 Rendered devise/shared/_links.erb (0.1ms) Rendered devise/registrations/new.html.erb within layouts/application (2.3ms) Rendered layouts/_landing.html.erb (1.5ms) Completed 200 OK in 8.9ms (Views: 7.5ms | ActiveRecord: 0.0ms)


Corto y simple:

request.remote_ip


En mi opinión, tu enfoque actual es el único sensato. El único paso que falta es sobrescribir la dirección IP en env .

El REMOTE_ADDR típico rara vez tiene la IP correcta si tiene cualquier cantidad de capas de proxies y equilibradores de carga y lo que no, no es único en este sentido. Cada uno potencialmente agrega o cambia los encabezados remotos relacionados con IP. Y no puede suponer que cada uno de esos campos corresponde necesariamente a una única dirección IP. Algunos presionarán o desharán una IP a una lista.

Solo hay una forma de saber con certeza qué campo tiene el valor correcto y cómo, y eso es bucear allí y mirar. Evidentemente ya has hecho eso. Ahora, simplemente sobrescriba env[''REMOTE_ADDR''] con su valor correcto usando su middleware Rack. No tiene sentido dejar que cualquier parte del código que no haya escrito log o procese la dirección IP incorrecta, como está sucediendo ahora.

(Esto es Ruby, también puedes parche de mono Rack :: Solicitud, por supuesto ...)

Para una lectura colorida que ilustre los diversos grados en los que las configuraciones exóticas pueden arruinar los intentos de encontrar la dirección IP real de un cliente, consulte, por ejemplo, las discusiones interminables que ocurrieron sobre esto con WordPress:

Es PHP, pero la esencia de los puntos planteados se aplica igualmente a Ruby. (Tenga en cuenta que no están resueltos mientras escribo esto, también, y que han existido por eones).


Estaba enfrentando el mismo problema. Para solucionar este problema, hice referencia a su implementación, justo debajo de la línea en config/application.rb lo arregló.

config.middleware.insert_before Rails::Rack::Logger, ''RemoteIpLogger''

No es necesario escribir extra loggers, verá IP del cliente real en la primera fila.

Started GET "/" for 10.0.10.62 at 2013-11-22 08:01:17 +0000

Y en la app/middleware/remote_ip_logger.rb . Mi HTTP_X_FORWARDED_FOR está teniendo una lista de IP y la primera es la IP del cliente real.

class RemoteIpLogger def initialize(app) @app = app end def call(env) if env["HTTP_X_FORWARDED_FOR"] remote_ip = env["HTTP_X_FORWARDED_FOR"].split(",")[0] env[''REMOTE_ADDR''] = env["action_dispatch.remote_ip"] = env["HTTP_X_FORWARDED_FOR"] = remote_ip @app.call(env) else @app.call(env) end end end


Esto pareció hacer el truco para mí. (establecido en configuración nginx)

proxy_set_header CLIENT_IP $remote_addr;


Me encontré con el mismo problema, que un subconjunto de nuestros clientes web acceden a nuestra aplicación de rieles en (Rails 4.2.7) en nuestra red privada y recibimos informes de IP incorrectos. Entonces, pensé que agregaría lo que funcionó para nosotros para resolver el problema.

Encontré el problema 5223 de Rails que proporcionaba una mejor solución que el doble de registrar el IP como lo hace la pregunta. Por lo tanto, aplicamos el parche Rack para eliminar la red privada de la lista de servidores proxy de confianza de la siguiente manera:

module Rack class Request def trusted_proxy?(ip) ip =~ /^127/.0/.0/.1$/ end end end

Eso se dirige al controlador que registra la dirección IP incorrecta, la otra mitad de la corrección para garantizar que request.remote_ip se maneje correctamente. Para hacerlo, agregue lo siguiente a su config / environments / production.rb:

config.action_dispatch.trusted_proxies = [IPAddr.new(''127.0.0.1'')]