nginx real_ip_header und X-Forwarded-For scheinen falsch zu sein

58

Die Wikipedia-Beschreibung des HTTP-Headers X-Forwarded-Forlautet:

X-Forwarded-For: client1, proxy1, proxy2, ...

Die Nginx-Dokumentation für die Direktive real_ip_headerlautet teilweise:

Diese Anweisung legt den Namen des Headers fest, der für die Übertragung der Ersatz-IP-Adresse verwendet wird.
Im Falle von X-Forwarded-For verwendet dieses Modul die letzte IP im X-Forwarded-For-Header zum Ersetzen. [Betonung meiner]

Diese beiden Beschreibungen scheinen sich zu widersprechen. In unserem Szenario ist der X-Forwarded-ForHeader genau wie beschrieben - die "echte" IP-Adresse des Clients ist der Eintrag ganz links. Ebenso besteht das Verhalten von nginx darin, den am weitesten rechts stehenden Wert zu verwenden - was natürlich nur einer unserer Proxy-Server ist.

Mein Verständnis von X-Real-IPist , dass es sollte verwendet werden , um die zur Bestimmung tatsächliche Client - IP - Adresse - nicht der Proxy. Vermisse ich etwas oder ist das ein Fehler in Nginx?

Hat darüber hinaus jemand Vorschläge, wie die X-Real-IPÜberschrift den Wert ganz links anzeigen kann, wie in der Definition von angegeben X-Forwarded-For?

Kirk Woll
quelle

Antworten:

95

Ich glaube, der Schlüssel zur Lösung von X-Forwarded-For-Problemen, wenn mehrere IPs verkettet sind, ist die kürzlich eingeführte Konfigurationsoption real_ip_recursive(hinzugefügt in nginx 1.2.1 und 1.3.0). In den Nginx Realip-Dokumenten :

Wenn die rekursive Suche aktiviert ist, wird eine ursprüngliche Clientadresse, die mit einer der vertrauenswürdigen Adressen übereinstimmt, durch die letzte nicht vertrauenswürdige Adresse ersetzt, die im Anforderungsheaderfeld gesendet wurde.

nginx hat standardmäßig die letzte IP-Adresse in der Kette abgerufen, da dies die einzige war, von der angenommen wurde, dass sie vertrauenswürdig ist. Mit dem neuen real_ip_recursiveaktivierten und mit mehreren set_real_ip_fromOptionen können Sie jedoch mehrere vertrauenswürdige Proxys definieren, und es wird die letzte nicht vertrauenswürdige IP abgerufen.

Zum Beispiel mit dieser Konfiguration:

set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Und ein X-Forwarded-For-Header, der Folgendes ergibt:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx wählt nun 123.123.123.123 als IP-Adresse des Clients aus.

Nginx wählt nicht nur die am weitesten links stehende IP-Adresse aus und fordert Sie dazu auf, vertrauenswürdige Proxys explizit zu definieren, sondern verhindert auch das einfache Spoofing von IP-Adressen.

Angenommen, die tatsächliche IP-Adresse eines Clients lautet 123.123.123.123. Lassen Sie uns auch sagen, dass der Client nichts Gutes tut und er versucht, seine IP-Adresse zu fälschen 11.11.11.11. Sie senden eine Anfrage an den Server, wobei dieser Header bereits vorhanden ist:

X-Forwarded-For: 11.11.11.11

Da Reverse-Proxys dieser X-Forwarded-For-Kette einfach IPs hinzufügen, sehen sie beispielsweise so aus, wenn Nginx darauf zugreift:

X-Forwarded-For: 11.11.11.11, 123.123.123.123, 192.168.2.1, 127.0.0.1

Wenn Sie einfach die am weitesten links stehende Adresse abrufen, kann der Client die IP-Adresse leicht fälschen. Mit dem obigen Beispiel nginx config vertraut nginx jedoch nur den letzten beiden Adressen als Proxys. Dies bedeutet, dass nginx 123.123.123.123die IP-Adresse korrekt auswählt , obwohl diese gefälschte IP-Adresse die am weitesten links stehende ist.

Nick M
quelle
1
Vielen Dank dafür, es hat mir sehr geholfen. Dies sollte die akzeptierte Antwort sein.
José F. Romaniello
1
Standardmäßig scheint real_ip_header X-Real-IP gemäß nginx.org/en/docs/http/ngx_http_realip_module.html zu sein. Bedeutet dies, dass böswillige Benutzer nur Anfragen mit zufälliger X-Real-IP senden können und diese als $ remote_addr verwendet werden in Nginx (und möglicherweise auch an die Anwendung übergeben)?
Gansbrest
@gansbrest Nein, da set_real_ip_from die vertrauenswürdigen Hosts einschränkt.
El Yobo
9

Das Parsen des X-Forwarded-ForHeaders ist in der Tat im nginx real_ip-Modul fehlerhaft.

len = r->headers_in.x_forwarded_for->value.len;
ip = r->headers_in.x_forwarded_for->value.data;

for (p = ip + len - 1; p > ip; p--) {
  if (*p == ' ' || *p == ',') {
    p++;
    len -= p - ip;
    ip = p;
    break;
  }
}

Sie beginnt ganz rechts in der Kopfzeile. Sobald ein Leerzeichen oder Komma angezeigt wird, hört sie auf zu suchen und fügt den Teil rechts vom Leerzeichen oder Komma in die IP-Variable ein. Daher wird die neueste Proxy-Adresse als ursprüngliche Client- Adresse behandelt.

Es spielt sich nicht gut nach der Spezifikation; Dies ist die Gefahr, dass es in einem RFC nicht in schmerzlich offensichtlichen Worten formuliert wird.

Übrigens: Es ist schwierig, eine gute Primärquelle für das Format zu finden, das ursprünglich von Squid definiert wurde. Ein Blick in die Dokumentation bestätigt die Bestellung. Ganz links ist der ursprüngliche Client, ganz rechts der neueste Anhang. Ich bin sehr versucht , dieser Wikipedia-Seite ein [Zitat] hinzuzufügen . Eine anonyme Bearbeitung scheint die Autorität des Internets in diesem Bereich zu sein.

Können sich Ihre zwischengeschalteten Proxys nach Möglichkeit nicht mehr am Ende des Headers einfügen, sondern nur noch die tatsächliche Client-Adresse angeben?

Shane Madden
quelle
Danke für die Antwort, @Shane. Tatsächlich X-Forwarded-Forexistiert bereits ein, wenn Nginx erreicht wird . (es ist die richtige Client-IP-Adresse) nginx selbst fügt dann die IP-Adresse unseres Load Balancers (den vorherigen Hop) an den X-Forwarded-ForHeader an. (Vermutlich wird die "entfernte Adresse" angehängt.) Wenn dies nicht der Fall wäre, könnte ich den X-Forwarded-ForHeader wie zuvor verwenden. (Wir haben kürzlich
Kirk Woll
@ Kirk Also, wenn Nginx den Header bekommt, ist es nur die Adresse des ursprünglichen Kunden? Aber wenn es verarbeitet wird, wird es im Header des Verbindungs-Proxy-Servers hinzugefügt? Das summiert sich nicht - das einzige Mal, dass der Header berührt werden sollte, ist, wenn die Verbindung über a an einen anderen Proxy gesendet wird proxy_pass- und selbst dann nur mit proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;in place.
Shane Madden
Sogar das W3C versteht das falsch : In der Dokumentation heißt es "Proxies sollten die IP-Adresse des Initiators der Anforderung an das Ende einer durch Kommas getrennten Liste in einem X-Forwarded-For-HTTP-Header-Feld anfügen " und " Beginn" .
Ian Kemp
3
@ IanKemp, nein, Ende ist richtig. Für die Serverseite eines Proxys ist der Initiator der Anforderung (dh der TCP- Anforderung) der vorherige Proxy (falls vorhanden). Dieser vorherige Proxy sendet möglicherweise bereits einen X-Forwarded-ForHeader mit möglicherweise der ursprünglichen Client-Adresse auf der linken Seite und möglicherweise allen vorangegangenen Proxys, die daran angehängt sind. Der aktuell versorgende Proxy würde also den vorherigen Proxy (= Initiator) an das Ende dieser Liste anfügen und den so erweiterten X-Forwarded-ForHeader dem nächsten Upstream-Hop zuführen. Zugegeben, sie hätten eine offensichtlichere Formulierung wählen können.
Blubberdiblub
5

X-Real-IP ist die IP-Adresse des tatsächlichen Clients, mit dem der Server spricht (der "echte" Client des Servers), der im Fall einer Proxy-Verbindung der Proxy-Server ist. Deshalb enthält X-Real-IP die letzte IP im X-Forwarded-For-Header.

user558061
quelle
1
OK, aber für mich sind das einfach nie nützliche Informationen. Ich möchte die ursprüngliche IP-Adresse des Clients erhalten - das ist entscheidend und nach allem, was ich gelesen habe, der Zweck dieser Header. Warum sollte ich die IP-Adresse unserer Proxy-Server erfahren wollen?
Kirk Woll
Wenn es für dich nicht nützlich ist, dann ist es nicht für dich. Niemand zwingt Sie, X-Real-IP zu verwenden. Wenn Sie die IP des Benutzers in Ihrer Anwendung benötigen, lassen Sie Ihre Anwendung X-Forwarded-For analysieren (was nicht immer zuverlässig ist, da es einige Proxys (Internet Security Appliance / Firewalls) gibt, die X-Forwarded- nicht festlegen. Zum). Im Kontext von nginx ist X-Forwarded-For nicht wichtig, da es abgesehen vom letzten Eintrag (der X-Real-IP), der der Client von nginx ist, ohnehin nicht mit diesen Clients kommuniziert. Wenn du es nicht brauchst, setze es nicht, lösche es oder ignoriere es einfach: /
user558061
2
Nein, ich meine, warum sollte X-Real-IPes jemals nützlich sein, die IP-Adresse meines eigenen Proxy-Servers zurückzugeben ?
Kirk Woll
Toll .. antworte Mann. Ich habe genau nach diesen Informationen gesucht. Ich muss mit einem ncat-Server auf meinem Proxy-Server sprechen, also brauche ich dies im laufenden Betrieb.
Yugal Jindle