Express.js: So erhalten Sie die Remote-Client-Adresse


256

Ich verstehe nicht ganz, wie ich eine IP-Adresse eines Remotebenutzers erhalten soll.

Angenommen, ich habe eine einfache Anforderungsroute wie:

app.get(/, function (req, res){
   var forwardedIpsStr = req.header('x-forwarded-for');
   var IP = '';

   if (forwardedIpsStr) {
      IP = forwardedIps = forwardedIpsStr.split(',')[0];  
   }
});

Ist der obige Ansatz korrekt, um die tatsächliche Benutzer-IP-Adresse zu erhalten, oder gibt es einen besseren Weg? Und was ist mit Proxies?


1
Wie wäre es mit der Verwendung von Node-IPware gemäß der Erklärung hier .
Un33k

Wenn Sie req.hostname wie 'example.com' nicht erhalten können: stackoverflow.com/a/37824880/5333284
zhi.yang

Antworten:


469

Wenn Sie hinter einem Proxy wie NGiNX laufen oder was Sie haben, sollten Sie nur dann nach 'x-forwarded-for' suchen:

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

Wenn der Proxy nicht "Ihr" ist, würde ich dem "x-forwarded-for" -Header nicht vertrauen, da er gefälscht werden kann.


2
Dies ist richtig, aber in meiner Situation musste ich eckige Klammern verwenden (siehe oben). Stellen Sie außerdem sicher, dass in Ihrer Nginx-Konfiguration x-forwarded-for aktiviert ist. Klappt wunderbar!
Neunhundert

43
Sie müssen berücksichtigen, dass Sie diese Anweisung proxy_set_header X-Forwarded-For $remote_addr;in Ihre Nginx-Konfiguration einfügen müssen, falls Sie Ihren eigenen Reverse-Proxy verwenden.
Coxer

Wenn Sie vorhaben, die IP im Browser zu verwenden, dann http (s): // [ipv6]: port Beachten Sie, dass die [] benötigt werden, hoffe dies hilft
psuhas

43
Benutzer von Copy-Pasta beachten Sie bitte: Dies kann eine durch Kommas getrennte Liste von IP-Adressen zurückgeben. Wir hatten einen Fehler von einem Entwickler, der dies kopierte und das Ergebnis mit einer IP verglich. Vielleicht machen Sie so etwas wie var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();Client-IP zu bekommen.
Davy Jones

3
@Rishav :: 1 ist die IPv6-Adresse für localhost
Daniel O

238

Während die Antwort von @alessioalex funktioniert, gibt es einen anderen Weg, wie im Abschnitt Express hinter Proxys des Express-Leitfadens angegeben .

  1. Fügen Sie app.set('trust proxy', true)Ihrem Express-Initialisierungscode hinzu.
  2. Wenn Sie die IP des Remote-Clients erhalten möchten, verwenden Sie req.ipoder req.ipsauf die übliche Weise (als ob es keinen Reverse-Proxy gibt).

Optionale Lesung:

  • Verwenden Sie req.ipoder req.ips. req.connection.remoteAddressfunktioniert mit dieser Lösung nicht.
  • Weitere Optionen für 'trust proxy'stehen zur Verfügung, wenn Sie etwas Anspruchsvolleres benötigen, als alles zu vertrauen, was im x-forwarded-forHeader durchlaufen wird (z. B. wenn Ihr Proxy bereits vorhandene x-forwarded-for-Header nicht aus nicht vertrauenswürdigen Quellen entfernt). Weitere Informationen finden Sie in der verlinkten Anleitung.
  • Wenn Ihr Proxyserver keinen x-forwarded-forHeader ausfüllt, gibt es zwei Möglichkeiten.
    1. Der Proxyserver gibt die Informationen darüber, wo die Anforderung ursprünglich war, nicht weiter. In diesem Fall kann nicht herausgefunden werden, woher die Anforderung ursprünglich stammt. Sie müssen zuerst die Konfiguration des Proxyservers ändern.
      • Wenn Sie beispielsweise nginx als Reverse-Proxy verwenden, müssen Sie möglicherweise proxy_set_header X-Forwarded-For $remote_addr;Ihre Konfiguration erweitern.
    2. Der Proxyserver gibt die Informationen darüber, woher die Anforderung ursprünglich stammte, proprietär weiter (z. B. benutzerdefinierten http-Header). In diesem Fall würde diese Antwort nicht funktionieren. Es gibt möglicherweise eine benutzerdefinierte Methode, um diese Informationen zu erhalten, aber Sie müssen zuerst den Mechanismus verstehen.

4
Meine Antwort war allgemeiner (nicht an Express gebunden), aber wenn Sie Express verwenden, ist dies in der Tat der bessere Weg.
Alessioalex

4
Auf Ihrem Proxyserver muss der Header 'x-forwarded-for' auf die Remote-Adresse gesetzt sein. Im Fall von Nginx sollten Sie beispielsweise proxy_set_header X-Forwarded-For $ remote_addr in Ihrer Konfigurationsdatei haben
Kamagatos

1
Hinter IIS mit IISnode als Proxy app.enable('trust proxy')funktioniert auch zu verwenden req.ip. Außer ich bekomme den Port damit 1.2.3.4:56789. Um das zu entfernen, mache ichvar ip = req.ip.split(':')[0]
Christiaan Westerbeek

Ist diese Lösung sicher?
Daniel Kmak

3
Ich bin der Meinung, dass diese Antwort nicht sicher ist und aktualisiert werden muss. Sie sollten IMMER definieren, welchen Proxys Ihre Anwendung vertraut. Die akzeptierte Antwort hat zumindest ein wenig Hinweis auf Spoofing. Das heißt, es ist eine bessere Lösung, eine Bibliothek wie diese zu verwenden, wenn Sie Express verwenden, aber der angegebene Code ist falsch und wird nicht in der verknüpften Ressource gefunden.
Phil

54

In nginx.confDatei:
proxy_set_header X-Real-IP $remote_addr;

In der node.jsServerdatei:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

Beachten Sie, dass Kleinbuchstaben ausgedrückt werden


3
Willkommen bei Stack Overflow! Erklären Sie bitte, warum dieser Code das aufgeworfene Problem löst, anstatt nur einen Codeblock zu veröffentlichen. Ohne eine Erklärung ist dies keine Antwort.
Artemix

1
Die Antwort von @ququzone ist in Ordnung. Die Erklärung ist ein benutzerdefinierter Header für die Anforderung mit dem Namen "x-real-ip", der die ursprüngliche IP-Adresse vom Besucher übernimmt. Es funktioniert bei mir mit node und socket.io.
Coffekid

8
Für mich ist die IP-Adresse verfügbar, auch req.headers['x-real-ip']wenn der nginx.confHeader mit Großbuchstaben gesetzt ist.
Nik Sumeiko

Das hat es für mich gelöst. Selbst wenn der Trust-Proxy auf true gesetzt war, wurde immer noch die lokale 127.0.0.1-Adresse verwendet
David

30

Insbesondere für Knoten heißt es in der Dokumentation für die http-Serverkomponente unter Ereignisverbindung :

[Ausgelöst], wenn ein neuer TCP-Stream eingerichtet wird. Der Socket [The] ist ein Objekt vom Typ net.Socket. Normalerweise möchten Benutzer nicht auf dieses Ereignis zugreifen. Insbesondere gibt der Socket keine lesbaren Ereignisse aus, da der Protokollparser eine Verbindung zum Socket herstellt. Auf die Steckdose kann auch unter zugegriffen werden request.connection.

Das heißt also, es request.connectionhandelt sich um einen Socket, und gemäß der Dokumentation gibt es tatsächlich ein socket.remoteAddress- Attribut, das gemäß der Dokumentation lautet:

Die Zeichenfolgendarstellung der Remote-IP-Adresse. Zum Beispiel '74 .125.127.100 'oder' 2001: 4860: a005 :: 68 '.

Unter Express ist das Anforderungsobjekt auch eine Instanz des Node http-Anforderungsobjekts, daher sollte dieser Ansatz weiterhin funktionieren.

Unter Express.js hat die Anforderung jedoch bereits zwei Attribute: req.ip und req.ips

req.ip

Geben Sie die Remote-Adresse zurück oder, wenn "Trust Proxy" aktiviert ist - die Upstream-Adresse.

req.ips

Wenn "Trust Proxy"true aktiviert ist , analysieren Sie die IP-Adressliste "X-Forwarded-For" und geben Sie ein Array zurück. Andernfalls wird ein leeres Array zurückgegeben. Wenn der Wert beispielsweise "client, proxy1, proxy2" wäre, würden Sie das Array ["client", "proxy1", "proxy2"] erhalten, wobei "proxy2" am weitesten stromabwärts liegt.

Es kann erwähnenswert sein, dass der Express nach meinem Verständnis req.ipein besserer Ansatz ist als req.connection.remoteAddress, da er req.ipdie tatsächliche Client-IP enthält (vorausgesetzt, dass der vertrauenswürdige Proxy in Express aktiviert ist), während der andere möglicherweise die IP-Adresse des Proxys enthält (falls vorhanden) einer).

Aus diesem Grund schlägt die derzeit akzeptierte Antwort vor:

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

Das req.headers['x-forwarded-for']wird das Äquivalent von Express sein req.ip.



7

Dies sind nur zusätzliche Informationen für diese Antwort .

Wenn Sie verwenden nginx, würden Sie proxy_set_header X-Real-IP $remote_addr;den Standortblock für die Site hinzufügen . /etc/nginx/sites-available/www.example.combeispielsweise. Hier ist ein Beispiel für einen Serverblock.

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    location / {
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_pass http://127.0.1.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Nach dem Neustart nginxkönnen Sie auf die IP in Ihren node/ expressAnwendungsrouten mit zugreifenreq.headers['x-real-ip'] || req.connection.remoteAddress;


3

Laut Express hinter Proxies , req.ipberücksichtigt hat Reverse - Proxy genommen , wenn Sie so konfiguriert haben , trust proxyrichtig. Daher ist es besser als req.connection.remoteAddressdas, was von der Netzwerkschicht erhalten wird und kein Proxy kennt.


3

Zu diesem Zweck habe ich ein Paket geschrieben. Sie können es als Express-Middleware verwenden. Mein Paket wird hier veröffentlicht: https://www.npmjs.com/package/express-ip

Sie können das Modul mit installieren

npm i express-ip

Verwendung

const express = require('express');
const app = express();
const expressip = require('express-ip');
app.use(expressip().getIpInfoMiddleware);

app.get('/', function (req, res) {
    console.log(req.ipInfo);
});

1
Sie müssen die Zugehörigkeit im Beitrag offenlegen, wenn Sie auf etwas verlinken, mit dem Sie verbunden sind. Wenn Sie keine Zugehörigkeit offenlegen, wird dies als Spam betrachtet. Die Offenlegung muss explizit erfolgen, muss jedoch nicht formal sein (z. B. für Ihren persönlichen Inhalt: "auf meiner Website ...", "auf meinem Blog ..." usw.). Siehe: Was bedeutet "gute" Eigenwerbung? , einige Tipps und Ratschläge zur Eigenwerbung , Was ist die genaue Definition von "Spam" für Stapelüberlauf? und was macht etwas Spam .
Makyen

2

Ich weiß, dass diese Frage beantwortet wurde, aber hier ist, wie ich meine zum Arbeiten gebracht habe.

let ip = req.connection.remoteAddress.split(`:`).pop();

2

Wenn Sie die Bibliothek eines Drittanbieters verwenden können. Sie können request-ip überprüfen .

Sie können es von verwenden

import requestIp from 'request-ip';

app.use(requestIp.mw())

app.use((req, res) => {
  const ip = req.clientIp;
});

Der Quellcode ist ziemlich lang, daher werde ich ihn hier nicht kopieren. Sie können ihn unter https://github.com/pbojinov/request-ip/blob/master/src/index.js überprüfen

Grundsätzlich,

Es sucht nach bestimmten Headern in der Anforderung und greift auf einige Standardeinstellungen zurück, wenn diese nicht vorhanden sind.

Die Benutzer-IP wird in der folgenden Reihenfolge festgelegt:

  1. X-Client-IP
  2. X-Forwarded-For (Der Header kann mehrere IP-Adressen im Format "Client-IP, Proxy-1-IP, Proxy-2-IP" zurückgeben, daher nehmen wir die erste.)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip (Schneller CDN- und Firebase-Hosting-Header, wenn auf eine Cloud-Funktion verwiesen wird)
  5. True-Client-Ip (Akamai und Cloudflare)
  6. X-Real-IP (Nginx-Proxy / FastCGI)
  7. X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray)
  8. X-Forwarded, Forwarded-ForUnd Forwarded(Variations of # 2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Wenn eine IP-Adresse nicht gefunden werden kann, wird sie zurückgegeben null.

Offenlegung: Ich bin nicht mit der Bibliothek verbunden.


1

Das hat bei mir besser funktioniert als bei den anderen. Meine Websites stehen hinter CloudFlare und es schien erforderlich zu sein cf-connecting-ip.

req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress

Ich habe Express nicht hinter Proxys getestet, da es nichts über diesen cf-connecting-ipHeader aussagt.


1

Mit der Unterstützung von Could-Flare, Nginx und X-Real-IP

var user_ip;

    if(req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
      let first = req.headers['cf-connecting-ip'].split(', ');
      user_ip = first[0];
    } else {
      let user_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }

1

In meinem Fall habe ich ähnlich wie bei dieser Lösung den folgenden x-forwarded-for- Ansatz verwendet:

let ip = (req.headers['x-forwarded-for'] || '').split(',')[0];

x-forwarded-forDer Header fügt weiterhin die Route der IP vom Ursprung bis zum endgültigen Zielserver hinzu. Wenn Sie also die IP des Ursprungsclients abrufen müssen, ist dies das erste Element des Arrays.


0

var ip = req.connection.remoteAddress;

ip = ip.split (':') [3];


Ausgabe ist wie: - :: ffff: XXX.XX.XX.XX von diesem erhalten wir ip
Bhulawat Ajay

3
Ich denke, ip = ip.split(':').pop();wird in diesem Fall Teig sein, wenn normale IP, dh 127.0.0.1, kommt. Es wird immer noch in der Lage sein, Ihnen IP zu geben.
9me

0

Das Header-Objekt enthält alles, was Sie benötigen. Führen Sie dazu Folgendes aus:

var ip = req.headers['x-forwarded-for'].split(',')[0];

0

Alles zusammen witk @kakopappa Lösung plus morganProtokollierung der Client-IP-Adresse:

morgan.token('client_ip', function getId(req) {
    return req.client_ip
});
const LOG_OUT = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" :client_ip'
self.app.use(morgan(LOG_OUT, {
    skip: function(req, res) { // custom logging: filter status codes
        return res.statusCode < self._options.logging.statusCode;
    }
}));

// could-flare, nginx and x-real-ip support
var getIpInfoMiddleware = function(req, res, next) {
    var client_ip;
    if (req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
        var first = req.headers['cf-connecting-ip'].split(', ');
        client_ip = first[0];
    } else {
        client_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }
    req.client_ip = client_ip;
    next();
};
self.app.use(getIpInfoMiddleware);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.