2013-08-16 9 views
19

Auf Heroku Cedar wollte ich die IP des Clients erhalten. Erster Versuch:Erhalten Sie die echte IP-Adresse des Clients auf Heroku

Das funktioniert natürlich nicht, da alle Anfragen über Proxies weitergeleitet werden. Also die Alternative war:

ENV['HTTP_X_FORWARDED_FOR'] 

Aber das ist nicht ganz sicher, oder?

Wenn es nur einen Wert enthält, nehme ich dies. Wenn es mehr als einen Wert (durch Komma getrennt) enthält, könnte ich den ersten nehmen.

Aber was, wenn jemand diesen Wert manipuliert? Ich kann ENV['HTTP_X_FORWARDED_FOR'] nicht vertrauen, wie ich mit ENV['REMOTE_ADDR'] konnte. Und es gibt auch keine Liste von vertrauenswürdigen Proxys, die ich verwenden könnte.

Aber es muss eine Möglichkeit geben, um immer die IP-Adresse des Clients zuverlässig zu erhalten. Kennst du einen?

In their docs beschreibt Heroku, dass X-Forwarded-For "die ursprüngliche IP-Adresse des Clients ist, der eine Verbindung zum Heroku-Router herstellt".

Das klingt, als könnte Heroku die X-Forwarded-For mit der ursprünglichen Remote-IP überschreiben. Das würde Spoofing verhindern, oder? Kann das jemand bestätigen?

+0

Es tut mir leid, aber welche Sprache ist das? Wenn es nicht Python ist, wie mache ich das in Python? – Cubetastic

Antwort

26

Von Jacob, Heroku Director of Security damals:

Der Router nicht überschreibt X-Forwarded-For, aber es garantiert, dass der wahre Ursprung wird das letzte Element in der Liste immer sein.

Das bedeutet, dass, wenn Sie eine Heroku App auf normale Weise zugreifen, werden Sie in den X-Forwarded-For Header sehen Ihre IP-Adresse nur:

$ curl http://httpbin.org/ip 
{ 
    "origin": "123.124.125.126", 
} 

Wenn Sie versuchen, die IP, Ihre angeblich zu fälschen Herkunft ist reflektiert, aber - kritisch - so ist Ihre echte IP. Offensichtlich ist dies alles, was wir brauchen, so ist es eine klare und sichere Lösung für das Erhalten des IP-Adresse des Clients auf Heroku:

$ curl -H"X-Forwarded-For: 8.8.8.8" http://httpbin.org/ip 
{ 
    "origin": "8.8.8.8, 123.124.125.126" 
} 

Das ist genau das Gegenteil von what is described on Wikipedia, nebenbei bemerkt.

PHP Implementierung:

function getIpAddress() { 
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { 
     $ipAddresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); 
     return trim(end($ipAddresses)); 
    } 
    else { 
     return $_SERVER['REMOTE_ADDR']; 
    } 
} 
+0

https://devcenter.heroku.com/articles/http-routing wird nicht so detailliert behandelt wie Ihr Post, kann aber für Personen interessant sein, die überprüfen möchten, ob sich das Verhalten geändert hat. Das Schöne daran ist, dass die Rails RemoteIp Middleware korrekt funktioniert und die letzte vertrauenswürdige IP zurückgibt, die der Client oder der nicht vertrauenswürdige Proxy ist, den sie durchlaufen haben, ohne dass Heroku Proxy-Adressen konfiguriert werden müssen. – nruth

+0

Ich glaube nicht, dass das Beispiel, das du gibst, das Gegenteil von dem ist, was Wikipedia sagt (jetzt zumindest). Der Client verbindet sich mit 8.8.8.8 in der Kopfzeile mit heroku, was im Wesentlichen vortäuscht, dass es ein Proxy ist, der eine Anfrage von 8.8.8.8 weiterleitet, dann hängt heroku die IP der Verbindung, die er empfängt, an die Liste an. Oder in ihrem Listenbeispiel ist eine normale Anfrage [Client], und eine gefälschte ist [fakeclient, client]. Es werden keine Proxy-IPs eingefügt, da Heroku nur einen Proxy verwendet. – nruth

+0

@nruth Was ich meinte ist, dass Wikipedia sagt "die linksesten sind die ursprünglichen Kunden" während Heroku sagt "der wahre Ursprung wird immer der letzte Punkt in der Liste sein". – caw

3

Sie können niemals wirklich auf Informationen vertrauen, die vom Client kommen. Es geht eher darum, wem Sie vertrauen und wie Sie es verifizieren. Sogar Heroku kann möglicherweise beeinflusst werden, um einen schlechten HTTP_X_FORWARDED_FOR Wert zu liefern, wenn sie einen Fehler in ihrem Code haben oder sie irgendwie gehackt werden. Eine andere Option wäre ein anderer Heroku-Computer, der sich intern mit Ihrem Server verbindet und dessen Proxy komplett umgeht, während er REMOTE_ADDR und/oder HTTP_X_FORWARDED_FOR vortäuscht.

Die beste Antwort hier hängt davon ab, was Sie versuchen zu tun. Wenn Sie versuchen, Ihre Clients zu verifizieren, ist ein clientseitiges Zertifikat möglicherweise eine geeignetere Lösung. Wenn Sie nur die IP-Adresse für Geo-Location benötigen, kann es gut sein, dass Sie der Eingabe vertrauen. Im schlimmsten Fall wird jemand den Standort fälschen und den falschen Inhalt bekommen ... Wenn Sie einen anderen Anwendungsfall haben, gibt es viele andere Lösungen zwischen diesen beiden Extremen.

+1

Danke! Ich frage nur, weil Heroku die echte IP des Clients kennt.Dies ist nur die IP, von der Herokus Proxy die Anfrage erhalten hat. Wenn _that_ erneut ein Proxy ist, müssen wir uns nicht darum kümmern. Dies ist die normale Situation, die Sie auch mit "REMOTE_ADDR" haben würden, wenn sich der Client hinter einem Proxy befindet. Heroku, das gehackt wird oder einen Fehler in seinem Code hat, ist eine Ausnahme und das sollte uns auch nicht interessieren. Weil wir nichts dagegen tun können. Aber wenn Heroku nur das 'HTTP_X_FORWARDED_FOR _überschreiben würde, würden wir immer die echte IP-Adresse des Clients kennen, die wir normalerweise mit' REMOTE_ADDR' bekommen würden. Recht? – caw

+0

Ja, das ist richtig. Ein bisschen mehr dazu gibt es auf [Wikipedia] (http://en.wikipedia.org/wiki/X-Forwarded-For). – kichik

19

ich in Heroku die Support-Abteilung arbeiten und haben einige Zeit Sprache mit unserer Routing-Ingenieure ausgegeben. Ich wollte einige zusätzliche Informationen posten, um einige Dinge darüber zu klären, was hier vor sich geht.

Das Beispiel in der Antwort oben hatte nur die Client-IP zuletzt zufällig angezeigt und das ist nicht wirklich garantiert. Der Grund, warum es nicht der erste war, ist, dass die Ursprungsanforderung behauptete, dass sie für die IP-Adresse weitergeleitet wurde, die in dem Header X-Forwarded-For angegeben ist. Wenn der Heroku-Router die Anforderung erhalten hat, hat er die IP-Adresse, die direkt mit der X-Forwarded-For-Liste verbunden war, an die Liste angehängt, die in die Anfrage eingefügt wurde. Unser Router fügt immer die IP, die mit dem AWS ELB vor unserer Plattform verbunden ist, als letzte IP in der Liste hinzu. Diese IP könnte die ursprüngliche sein (und in dem Fall, wo es nur eine IP gibt, ist es fast sicher), aber in dem Moment, in dem mehrere IPs verkettet sind, sind alle Wetten ausgeschaltet. Konvention ist immer die letzte IP in der Kette am Ende der Liste hinzuzufügen (was wir tun), aber an jedem Punkt entlang der Kette kann diese Kette geändert werden und verschiedene IPs können eingefügt werden. Daher ist die einzige IP, die zuverlässig ist (aus der Perspektive unserer Plattform), die letzte IP in der Liste.

veranschaulicht, um, sagen sie mal jemand eine Anfrage initiiert und fügt beliebig 3 zusätzlichen IPs zum X-Forwarded-For-Header:

curl -H "X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4" http://www.google.com 

Stellen Sie sich diese IP 9.9.9.9 war die Maschine und es mußte passieren ein Proxy (z. B. der campusweite Proxy einer Universität). Angenommen, der Proxy hatte eine IP von 2.2.2.2. Angenommen, es wurde nicht konfiguriert, um X-Forwarded-For Header zu entfernen (was es wahrscheinlich nicht wäre), würde es einfach die 9.9.9.9 IP an das Ende der Liste heften und die Anfrage an Google weiterleiten. An diesem Punkt würde der Header wie folgt aussehen:

X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4,9.9.9.9 

Dieser Antrag wird dann durch die Google-Endpunkt übergeben, die die Universität Proxy-IP von 2.2.2.2 wird anhängen, so schließlich der Header wie dies in den Google-Protokolle aussehen :

X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4,9.9.9.9,2.2.2.2 

Also, welches ist der Client IP? Es ist unmöglich, aus dem Standpunkt von Google zu sagen. In Wirklichkeit ist die Client-IP 9.9.9.9. Die letzte aufgelistete IP ist 2.2.2.2 und die erste ist 12.12.12.12. Alles, was Google wissen würde, ist, dass die 2.2.2.2 IP definitiv korrekt ist, weil das die IP war, die tatsächlich mit ihrem Dienst verbunden war - aber sie würden nicht wissen, ob das der anfängliche Client für die Anfrage war oder nicht aus den verfügbaren Daten. Genauso gibt es nur eine IP in dieser Kopfzeile - das ist die IP, die direkt mit unserem Dienst verbunden ist, also wissen wir, dass es zuverlässig ist.

Aus einem praktischen Standpunkt wird diese IP wahrscheinlich zuverlässig sein die meiste Zeit (weil die meisten Leute nicht stören werden, ihre IP zu spoofen). Leider ist es unmöglich, diese Art von Spoofing zu verhindern, und zu dem Zeitpunkt, zu dem eine Anfrage an den Heroku-Router kommt, können wir unmöglich feststellen, ob IPs in einer X-Forwarded-For-Kette manipuliert wurden oder nicht.

Abgesehen von allen Zuverlässigkeitsproblemen sollten diese IP-Ketten immer von links nach rechts gelesen werden. Der Client IP sollte immer die linke IP sein.

+2

Ich habe bis zum letzten Absatz weitergemacht. Sollte das heißen, dass IP-Ketten von rechts nach links gelesen werden sollten und dass die Client-IP die rechte IP sein sollte? – Aaron

+0

Die Client-IP ist die am weitesten links gelegene IP-Adresse. Konvention ist, dass zusätzliche IPs an die Liste angehängt werden, wenn sie angetroffen werden, so dass die allererste IP in der Liste in den meisten Fällen die tatsächliche Client-IP sein sollte. Andere IPs in der Liste sind Zwischenprodukte. Bedenken Sie jedoch, dass die IPs in der Liste an beliebiger Stelle in der Anforderungskette beliebig geändert werden können. Daher ist es nicht garantiert, dass die IP korrekt ist. –

+0

Also würde im obigen Beispiel "12.12.12.12" als IP des Clients betrachtet, obwohl es "9.9.9.9" ist, weil sie absichtlich die zusätzlichen IPs zum Header hinzugefügt haben? – Aaron