Express.js: come ottenere l'indirizzo client remoto


256

Non capisco completamente come dovrei ottenere un indirizzo IP per l'utente remoto.

Diciamo che ho un semplice percorso di richiesta come:

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

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

L'approccio sopra è corretto per ottenere l'indirizzo IP dell'utente reale o esiste un modo migliore? E i proxy?


1
Che ne dici di usare node-ipware secondo la spiegazione qui .
un33k,

se non è possibile ottenere req.hostname come 'example.com': stackoverflow.com/a/37824880/5333284
zhi.yang

Risposte:


469

Se stai eseguendo un proxy come NGiNX o quello che hai, solo allora dovresti controllare 'x-forwarded-for':

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

Se il proxy non è "tuo", non mi fiderei dell'intestazione "x-forwarded-for", perché può essere falsificato.


2
Questo è corretto, tuttavia nella mia situazione ho dovuto usare parentesi quadre (vedi sopra modifica) Assicurati anche che x-forwarded-for sia abilitato nella tua configurazione nginx. Funziona come un fascino!
Novecento

43
È necessario tenere presente che è necessario inserire questa direttiva proxy_set_header X-Forwarded-For $remote_addr;nella configurazione di nginx nel caso in cui si stia utilizzando il proprio proxy inverso.
Coxer,

Se prevedi di utilizzare l'IP nel browser, allora http (s): // [ipv6]: port Nota che [] sono necessari, spero che questo aiuti
psuhas

43
Nota per gli utenti di copia-pasta: questo può restituire un elenco separato da virgole di indirizzi IP. Abbiamo avuto un bug da uno sviluppatore che lo copiava e confrontava il risultato con un IP. Forse fai qualcosa di simile var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();per ottenere l'IP client.
Davy Jones,

3
@Rishav :: 1 è l'indirizzo IPv6 per localhost
Daniel O

238

Mentre la risposta di @alessioalex funziona, c'è un altro modo, come affermato nella sezione Express dietro i proxy di Express - guida .

  1. Aggiungi app.set('trust proxy', true)al tuo codice di inizializzazione espresso.
  2. Quando vuoi ottenere l'ip del client remoto, usa req.ipo req.ipsnel solito modo (come se non ci fosse un proxy inverso)

Lettura opzionale:

  • Usa req.ipo req.ips. req.connection.remoteAddressnon funziona con questa soluzione.
  • Sono disponibili più opzioni 'trust proxy'se hai bisogno di qualcosa di più sofisticato della fiducia in tutto ciò che è passato x-forwarded-fornell'intestazione (ad esempio, quando il tuo proxy non rimuove l'intestazione x-forwarded-for preesistente da fonti non attendibili). Vedi la guida collegata per maggiori dettagli.
  • Se il server proxy non popola l' x-forwarded-forintestazione, ci sono due possibilità.
    1. Il server proxy non inoltra le informazioni su dove era originariamente la richiesta. In questo caso, non ci sarebbe modo di scoprire da dove provenisse la richiesta. È necessario modificare prima la configurazione del server proxy.
      • Ad esempio, se si utilizza nginx come proxy inverso, potrebbe essere necessario aggiungere proxy_set_header X-Forwarded-For $remote_addr;alla propria configurazione.
    2. Il server proxy inoltra le informazioni sulla provenienza della richiesta in modo proprietario (ad esempio, intestazione http personalizzata). In tal caso, questa risposta non funzionerebbe. Potrebbe esserci un modo personalizzato per ottenere tali informazioni, ma è necessario prima capire il meccanismo.

4
La mia risposta è stata più generale (non legata a Express), ma se stai usando Express è davvero il modo migliore.
alessioalex,

4
Il tuo server proxy deve avere l'intestazione 'x-forwarded-for' impostata sull'indirizzo remoto. Nel caso di nginx, ad esempio, dovresti avere proxy_set_header X-Forwarded-For $ remote_addr nel tuo file di configurazione
Kamagatos

1
Dietro IIS con IISnode come proxy, app.enable('trust proxy')funziona anche da usare req.ip. Solo che ho il porto con esso 1.2.3.4:56789. Per toglierlo, lo facciovar ip = req.ip.split(':')[0]
Christiaan Westerbeek il

Questa soluzione è sicura?
Daniel Kmak,

3
Ritengo che questa risposta manchi di sicurezza e debba essere aggiornata. Dovresti SEMPRE definire quali proxy sono attendibili dalla tua applicazione. La risposta accettata ha almeno un piccolo preavviso sullo spoofing. Detto questo, è una soluzione migliore utilizzare una libreria come questa se si utilizza express, ma il codice citato non è corretto e non si trova sulla risorsa collegata.
Phil,

54

Nel nginx.conffile:
proxy_set_header X-Real-IP $remote_addr;

Nel node.jsfile del server:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

notare che esprimono le intestazioni minuscole


3
Benvenuto in Stack Overflow! Invece di pubblicare solo un blocco di codice, spiega perché questo codice risolve il problema posto. Senza una spiegazione, questa non è una risposta.
Artemix,

1
La risposta di @ququzone è ok. La spiegazione è impostata un'intestazione personalizzata sulla richiesta denominata "x-real-ip" che prende l'indirizzo IP originale dal visitatore. Funziona per me con node e socket.io.
coffekid,

8
Per me, l'indirizzo IP è disponibile req.headers['x-real-ip']anche nginx.confnell'intestazione è impostato con lettere maiuscole.
Nik Sumeiko,

Questo è ciò che ha risolto per me. Anche con il proxy di fiducia impostato su true, utilizzava ancora l'indirizzo 127.0.0.1 locale
David,

30

Soprattutto per il nodo, la documentazione per il componente server http, sotto la connessione dell'evento dice:

[Triggered] quando viene stabilito un nuovo flusso TCP. [Il] socket è un oggetto di tipo net.Socket. Di solito gli utenti non vorranno accedere a questo evento. In particolare, il socket non emetterà eventi leggibili a causa di come il parser di protocollo si collega al socket. È possibile accedere al socket anche all'indirizzo request.connection.

Quindi, ciò significa che request.connectionè un socket e secondo la documentazione esiste effettivamente un attributo socket.remoteAddress che secondo la documentazione è:

La rappresentazione in formato stringa dell'indirizzo IP remoto. Ad esempio, '74 .125.127.100 'o' 2001: 4860: a005 :: 68 '.

Sotto express, l'oggetto richiesta è anche un'istanza dell'oggetto richiesta http Node, quindi questo approccio dovrebbe ancora funzionare.

Tuttavia, in Express.js la richiesta ha già due attributi: req.ip e req.ips

req.ip

Restituisce l'indirizzo remoto o quando è abilitato "proxy di fiducia" - l'indirizzo upstream.

req.ips

Quando "proxy di fiducia" è true, analizzare l'elenco di indirizzi IP "X-Forwarded-For" e restituire un array, altrimenti viene restituito un array vuoto. Ad esempio, se il valore fosse "client, proxy1, proxy2" si riceverà l'array ["client", "proxy1", "proxy2"] dove "proxy2" è il downstream più lontano.

Vale la pena ricordare che, secondo la mia comprensione, Express req.ipè un approccio migliore rispetto a req.connection.remoteAddress, poiché req.ipcontiene l'ip client effettivo (a condizione che il proxy trusted sia abilitato in express), mentre l'altro può contenere l'indirizzo IP del proxy (se esiste uno).

Questo è il motivo per cui la risposta attualmente accettata suggerisce:

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

Il req.headers['x-forwarded-for']sarà l'equivalente di espresso req.ip.



7

Queste sono solo informazioni aggiuntive per questa risposta .

Se si utilizza nginx, è necessario aggiungere proxy_set_header X-Real-IP $remote_addr;al blocco posizione per il sito. /etc/nginx/sites-available/www.example.comper esempio. Ecco un esempio di blocco server.

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

Dopo il riavvio nginx, sarai in grado di accedere all'ip nei tuoi percorsi node/ expressapplication conreq.headers['x-real-ip'] || req.connection.remoteAddress;


3

Secondo Express behind proxy , req.ipha preso in considerazione il proxy inverso se è stato configurato trust proxycorrettamente. Pertanto è meglio di quello req.connection.remoteAddressche si ottiene dal livello di rete e ignaro del proxy.


3

Ho scritto un pacchetto a tale scopo. Puoi usarlo come middleware espresso. Il mio pacchetto è pubblicato qui: https://www.npmjs.com/package/express-ip

È possibile installare il modulo utilizzando

npm i express-ip

uso

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
Devi rivelare l'affiliazione nel post quando ti colleghi a qualcosa a cui sei affiliato. Se non divulga l'affiliazione, viene considerato spam. La divulgazione deve essere esplicita, ma non deve essere formale (ad es. Per i tuoi contenuti personali : "sul mio sito ...", "sul mio blog ...", ecc.). Vedi: Cosa significa autopromozione "buona"? , alcuni suggerimenti e consigli sull'autopromozione , Qual è la definizione esatta di "spam" per StackTranslate.it? e cosa rende spam qualcosa .
Makyen,

2

So che questa domanda ha avuto risposta, ma ecco come ho fatto funzionare la mia.

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

2

Se stai bene usando una libreria di terze parti. Puoi controllare request-ip .

Puoi usarlo è di

import requestIp from 'request-ip';

app.use(requestIp.mw())

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

Il codice sorgente è piuttosto lungo, quindi non copierò qui, puoi controllare su https://github.com/pbojinov/request-ip/blob/master/src/index.js

Fondamentalmente,

Cerca le intestazioni specifiche nella richiesta e torna ad alcune impostazioni predefinite se non esistono.

L'ip utente è determinato dal seguente ordine:

  1. X-Client-IP
  2. X-Forwarded-For (L'intestazione può restituire più indirizzi IP nel formato: "IP client, IP proxy 1, IP proxy 2", quindi prendiamo il primo.)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip (Intestazione rapida di hosting di CDN e Firebase quando viene notificato a una funzione cloud)
  5. True-Client-Ip (Akamai e Cloudflare)
  6. X-Real-IP (Proxy Nginx / FastCGI)
  7. X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray)
  8. X-Forwarded, Forwarded-ForE Forwarded(Variazioni di # 2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Se non è possibile trovare un indirizzo IP, verrà restituito null.

Divulgazione: non sono associato alla biblioteca.


1

Questo ha funzionato per me meglio degli altri. I miei siti sono dietro CloudFlare e sembrava richiedere cf-connecting-ip.

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

Non ho testato Express dietro i proxy perché non diceva nulla su questa cf-connecting-ipintestazione.


1

Con il supporto could-flare, nginx e 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

Nel mio caso, simile a questa soluzione, ho finito per usare il seguente approccio x-forwarded-for :

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

x-forwarded-forL'intestazione continuerà ad aggiungere la route dell'IP dall'origine fino al server di destinazione finale, quindi se è necessario recuperare l'IP del client di origine, questo sarebbe il primo elemento dell'array.


0

var ip = req.connection.remoteAddress;

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


ouput è come: - :: ffff: XXX.XX.XX.XX da questo otterremo ip
Bhulawat Ajay

3
Penso che ip = ip.split(':').pop();sarà un battitore in questo caso se arriverà un normale IP, cioè 127.0.0.1, sarà ancora in grado di darti un IP.
9

0

L'oggetto headers ha tutto ciò di cui hai bisogno, basta fare questo:

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

0

Mettendo insieme la soluzione witk @kakopappa più la morganregistrazione dell'indirizzo IP del client:

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.