So melden Sie echte client-ip-in-Schienen anmelden, wenn Sie sich hinter proxy wie nginx

Problem

Ich habe eine rails-3.2.15 mit rack-1.4.5-setup auf zwei Servern. Erste server wird ein nginx proxy statischen assets. Der zweite server ist ein Einhorn dienen die rails-app.

In Rails production.log ich sehe immer das nginx IP-Adresse (10.0.10.150) und nicht meine client-IP-Adresse (10.0.10.62):

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

Ich will die echte client-IP-Protokolle.

Unserem Setup

Den HTTP-Header X-Forwarded-For und X-Real-IP sind in der nginx-Konfiguration richtig und ich habe 10.0.10.62 nicht als einen vertrauenswürdigen proxy-Adresse Einstellung config.action_dispatch.trusted_proxies = /^127\.0\.0\.1$/ im config/environments/production.rb, Dank einem anderen Antwort. Kann ich kontrollieren, dass es funktioniert, weil ich log Sie in der application-controller:

in 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

in production.log:

request.ip = 10.0.10.150 and request.remote_ip = 10.0.10.62

Untersuchung

Bei der Untersuchung sah ich, dass Rails::Rack::Logger ist verantwortlich für die Protokollierung der IP-Adresse:

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 ist eine Instanz von ActionDispatch::Request. Es erbt Rack::Request, die bestimmt, wie die IP-Adresse berechnet wird:

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

Die Weiterleitung der IP-Adresse gefiltert werden, die mit trusted_proxy?. Weil unsere nginx-server ist über eine öffentliche IP-Adresse und nicht eine private IP-Adresse, Rack::Request#ip denkt, es ist kein proxy, sondern die echte client-ip, die versucht zu tun, einige IP-spoofing. Das ist, warum ich sehe nginx IP-Adresse in meinen logs.

In der log-Auszüge, client und Server haben die IP-Adresse 10.0.10.x weil ich mich mit virtuellen Maschinen zu reproduzieren unsere Produktionsumgebung.

Unsere aktuelle Lösung

Zur Umgehung dieses Verhalten, schrieb ich ein kleines Rack-middleware liegt in 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

Und ich legen Sie es kurz nach der ActionDispatch::RemoteIp middleware

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

Diese Weise kann ich sehen, die echte client-IP-Protokolle:

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

Ich fühle mich ein wenig unwohl mit dieser Lösung. nginx+unicorn ist ein gemeinsames setup für die rails-Anwendung. Wenn ich log die client IP selbst, es bedeutet, dass ich etwas verpasst haben. Ist es, weil der Nginx-server ist über eine öffentliche IP-Adresse bei der Kommunikation mit dem rails server? Gibt es eine Möglichkeit zum anpassen der trusted_proxy? Methode der Rack::Request?

BEARBEITET: hinzufügen nginx-Konfiguration, und ein HTTP-request capture

/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;
    }
}

Nginx server ist 10.0.10.150. Rails server ist 10.0.10.190. Meine Maschine ist 10.0.10.62 Wenn dabei curl http://10.0.10.150/ mit meiner Maschine, einer tcpdump port 8080 -i eth0 -Aq -s 0 on rails-server zeigen, Thesen Anfrage-HTTP-Header:

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: */*

Und die Schienen anmelden /home/deployer/site/current/log/production.log (Remote-IP - und Anfrage.die ip - Linien Hinzugefügt, die benutzerdefinierten code):

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)
  • was ist deine nginx config
  • Ich aktualisierte die Frage
InformationsquelleAutor cbliard | 2013-11-21
Schreibe einen Kommentar