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
Du musst angemeldet sein, um einen Kommentar abzugeben.
Meiner Meinung nach, Ihren aktuellen Ansatz ist die einzige vernünftige ein. Der einzige Schritt, der fehlt, ist ein überschreiben der IP-Adresse in
env
.Den typischen REMOTE_ADDR selten hält die richtige IP, wenn Sie haben jede Menge Schichten von Proxys und loadbalancern und was nicht-Sie sind nicht einzigartig in dieser Hinsicht. Jeweils möglicherweise Hinzugefügt oder geändert remote-IP-related Header. Und Sie können nicht davon ausgehen, dass jedes dieser Felder unbedingt entsprechen, um eine einzelne IP-Adresse an. Einige werden push und unshift eine IP-Adresse in einer Liste statt.
Es gibt nur einen Weg, sicher zu wissen, welche Feld enthält den richtigen Wert und wie, und das ist, Tauchen Sie dort, und Aussehen. Sie haben offensichtlich gemacht, das schon. Nun, einfach überschreiben
env['REMOTE_ADDR']
mit seinem richtigen Wert mit Ihrem Rack-middleware. Es gibt wenig Sinn, dass jede Stück code, den Sie nicht Protokoll schreiben, oder die falsche IP-Adresse, wie es jetzt geschieht.(Dies Ruby, Sie könnte auch monkey patch Rack::Request, natürlich...)
Für bunte Lektüre, die veranschaulichen, die in unterschiedlichem Ausmaß die exotischen setups kann mess up versucht, auf der Suche nach einem client die Reale IP-Adresse, siehe z.B. die endlosen Diskussionen, die stattgefunden hat, über dieses für WordPress:
Es ist PHP aber das wesentliche angesprochenen Punkte gelten genauso gut auf Ruby. (Beachten Sie, dass Sie ungelöst, während ich dies Schreibe, auch, und, dass Sie schon seit äonen.)
Dies schien, den trick zu tun für mich. (setzen Sie in der nginx-config)
proxy_set_header X-Forwarded-For $remote_addr;
im Abschnitt "Standort". Danke!!!Ich lief in das gleiche Problem, das eine Teilmenge von unserer web-clients Zugriff auf unsere rails app auf (Schienen 4.2.7) auf unserem privaten Netzwerk und wir bekommen die falsche IP gemeldet. So, ich dachte, ich würde hinzufügen, was für uns gearbeitet, um das problem zu beheben.
Fand ich Schienen-Ausgabe 5223, die einen besseren workaround als die doppelte Protokollierung der IP-wie der Frage hat. So, wir monkey patch Rack zu entfernen, die das private Netzwerk aus der Liste der vertrauenswürdigen proxies wie so:
Dass die Adressen der controller-Protokollierung die falsche IP, die andere Hälfte der fix, um sicherzustellen, dass
request.remote_ip
korrekt behandelt wird. Fügen Sie dazu Folgendes in deine config/environments/production.rb:Ich Stand vor dem gleichen problem. Um dies zu beheben ich bezog mich Ihre Umsetzung, nur unterhalb der Zeile in
config/application.rb
machte es fest.Nicht schreiben müssen extra Logger werden Sie sehen, dass die eigentliche client-IP in der ersten Zeile selbst.
Und in
app\middleware\remote_ip_logger.rb
. MeineHTTP_X_FORWARDED_FOR
ist eine Liste von IP-Adressen und die erste ist die eigentliche client-IP.Kurz und einfach :
request.remote_ip
und wie es zu lösen ist.