Express.js: cómo obtener la dirección del cliente remoto

256

No entiendo completamente cómo debo obtener una dirección IP de usuario remoto.

Digamos que tengo una ruta de solicitud simple como:

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

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

¿Es correcto el enfoque anterior para obtener la dirección IP del usuario real o hay una mejor manera? ¿Y qué hay de los poderes?

Erik
fuente
1
¿Qué tal usar node-ipware según la explicación aquí ?
un33k el
si no puede obtener req.hostname como 'example.com': stackoverflow.com/a/37824880/5333284
zhi.yang
1
Posible duplicado de Cómo determinar la dirección IP de un usuario en el nodo
Dan Dascalescu

Respuestas:

469

Si está ejecutando detrás de un proxy como NGiNX o lo que tiene, solo entonces debe verificar 'x-forwards-for':

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

Si el proxy no es 'tuyo', no confiaría en el encabezado 'x-forwards-for', porque puede ser falsificado.

alessioalex
fuente
2
Esto es correcto, sin embargo, en mi situación, tuve que usar corchetes (consulte la edición anterior). También asegúrese de tener x-forward-for habilitado en su configuración nginx. ¡Funciona de maravilla!
novecientos
43
Debe tener en cuenta que debe poner esta directiva proxy_set_header X-Forwarded-For $remote_addr;en su configuración nginx en caso de que esté utilizando su propio proxy inverso.
Coxer
Si va a usar la IP en el navegador luego http (s): // [IPv6]: Aviso puerto de [] son necesarios, espero que esta ayuda
psuhas
43
usuarios de copy-pasta, tenga en cuenta: Esto puede devolver una lista de direcciones IP separadas por comas. Tuvimos un error de un desarrollador al copiar esto y comparar el resultado con una IP. Quizás haga algo como var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();obtener la IP del cliente.
Davy Jones
3
@Rishav :: 1 es la dirección IPv6 para localhost
Daniel O
238

Si bien la respuesta de @alessioalex funciona, hay otra forma, como se indica en la sección Express detrás de proxies de Express - guía .

  1. Agregue app.set('trust proxy', true)a su código de inicialización express.
  2. Cuando desee obtener la ip del cliente remoto, use req.ipo req.ipsde la manera habitual (como si no hubiera un proxy inverso)

Lectura opcional:

  • Use req.ipo req.ips. req.connection.remoteAddressNo funciona con esta solución.
  • Hay más opciones 'trust proxy'disponibles si necesita algo más sofisticado que confiar en todo lo que se pasa en el x-forwarded-forencabezado (por ejemplo, cuando su proxy no elimina el encabezado x-forward-for preexistente de fuentes no confiables). Consulte la guía vinculada para más detalles.
  • Si su servidor proxy no llena el x-forwarded-forencabezado, hay dos posibilidades.
    1. El servidor proxy no transmite la información sobre dónde estaba originalmente la solicitud. En este caso, no habría forma de averiguar de dónde era originalmente la solicitud. Primero debe modificar la configuración del servidor proxy.
      • Por ejemplo, si usa nginx como su proxy inverso, es posible que deba agregar proxy_set_header X-Forwarded-For $remote_addr;a su configuración.
    2. El servidor proxy transmite la información sobre el origen de la solicitud originalmente (por ejemplo, encabezado http personalizado). En tal caso, esta respuesta no funcionaría. Puede haber una forma personalizada de obtener esa información, pero primero debe comprender el mecanismo.
Haozhun
fuente
44
Mi respuesta fue más general (no vinculada a Express), pero si está utilizando Express, esa es la mejor manera.
alessioalex
44
Su servidor proxy debe tener el encabezado 'x-forwards-for' establecido en la dirección remota. En el caso de nginx, por ejemplo, debe tener proxy_set_header X-Fordered-For $ remote_addr en su archivo de configuración
Kamagatos
1
Detrás de IIS con IISnode como proxy, app.enable('trust proxy')también funciona para usar req.ip. Excepto que consigo el puerto1.2.3.4:56789 . Para despojarme, lo hagovar ip = req.ip.split(':')[0]
Christiaan Westerbeek
¿Es segura esta solución?
Daniel Kmak
3
Siento que esta respuesta carece de seguridad y necesita actualización. SIEMPRE debe definir en qué servidores proxy confía su aplicación. La respuesta aceptada al menos tiene un pequeño aviso sobre la suplantación de identidad. Dicho esto, ES una mejor solución para usar una biblioteca como esta si está utilizando express, pero el código citado es incorrecto y no se encuentra en el recurso vinculado.
Phil
54

En nginx.confarchivo:
proxy_set_header X-Real-IP $remote_addr;

En el node.jsarchivo del servidor:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

tenga en cuenta que expresa encabezados en minúsculas

ququzone
fuente
3
¡Bienvenido a Stack Overflow! En lugar de solo publicar un bloque de código, explique por qué este código resuelve el problema planteado. Sin una explicación, esto no es una respuesta.
Artemix
1
La respuesta de @ququzone está bien. La explicación es establecer un encabezado personalizado en la solicitud llamada "x-real-ip" que toma la dirección IP original del visitante. A mí me funciona con node y socket.io.
coffekid
8
Para mí, la dirección IP está disponible req.headers['x-real-ip']incluso en el nginx.confencabezado se establece con letras mayúsculas.
Nik Sumeiko
Esto es lo que me resolvió. Incluso con el proxy de confianza establecido en verdadero, todavía estaba usando la dirección 127.0.0.1 local
David
30

Particularmente para el nodo, la documentación para el componente del servidor http, bajo conexión de evento dice:

[Activado] cuando se establece una nueva secuencia TCP. [El] socket es un objeto de tipo net.Socket. Por lo general, los usuarios no querrán acceder a este evento. En particular, el socket no emitirá eventos legibles debido a cómo el analizador de protocolo se conecta al socket. También se puede acceder al zócalo enrequest.connection .

Entonces, eso significa que request.connectiones un socket y de acuerdo con la documentación, de hecho, hay un atributo socket.remoteAddress que de acuerdo con la documentación es:

La representación de cadena de la dirección IP remota. Por ejemplo, '74 .125.127.100 'o' 2001: 4860: a005 :: 68 '.

Bajo express, el objeto de solicitud también es una instancia del objeto de solicitud http Node, por lo que este enfoque aún debería funcionar.

Sin embargo, en Express.js la solicitud ya tiene dos atributos: req.ip y req.ips

req.ip

Devuelva la dirección remota o cuando el "proxy de confianza" esté habilitado: la dirección ascendente.

req.ips

Cuando "proxy de confianza" es true, analice la lista de direcciones IP "X-Fordered-For" y devuelva una matriz, de lo contrario se devuelve una matriz vacía. Por ejemplo, si el valor fuera "cliente, proxy1, proxy2", recibiría la matriz ["cliente", "proxy1", "proxy2"] donde "proxy2" es el flujo descendente más alejado.

Vale la pena mencionar que, según tengo entendido, el Express req.ipes un mejor enfoque quereq.connection.remoteAddress , ya que req.ipcontiene la IP del cliente real (siempre que el proxy de confianza esté habilitado en express), mientras que el otro puede contener la dirección IP del proxy (si hay uno).

Esa es la razón por la cual la respuesta actualmente aceptada sugiere:

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

El req.headers['x-forwarded-for']será el equivalente de express req.ip.

Edwin Dalorzo
fuente
11
  1. Añadir app.set('trust proxy', true)
  2. Usar req.ipo req.ipsde la manera habitual
Calvo
fuente
2
Este es el camino a seguir. Consulte expressjs.com/en/guide/behind-proxies.html para obtener más detalles.
O. Jones
Tan fácil y conciso. Me encanta una respuesta simple.
gilbert-v
7

Esta es solo información adicional para esta respuesta .

Si está utilizando nginx, agregaría proxy_set_header X-Real-IP $remote_addr;al bloque de ubicación del sitio. /etc/nginx/sites-available/www.example.compor ejemplo. Aquí hay un ejemplo de bloque de servidor.

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

Después de reiniciar nginx, podrá acceder a la IP en sus rutas node/ expressaplicación conreq.headers['x-real-ip'] || req.connection.remoteAddress;

aprender más
fuente
3

Según Express detrás de los proxies , se req.ipha tenido en cuenta el proxy inverso si se ha configurado trust proxycorrectamente. Por lo tanto, es mejor que el req.connection.remoteAddressque se obtiene de la capa de red y desconoce el proxy.

abbr
fuente
3

Escribí un paquete para ese propósito. Puede usarlo como middleware express. Mi paquete se publica aquí: https://www.npmjs.com/package/express-ip

Puede instalar el módulo usando

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);
});
Oyetoke Tobi
fuente
1
Usted debe revelar la afiliación en el post cuando se enlaza a algo que está afiliado. Si no divulga su afiliación, se considera spam. La divulgación debe ser explícita, pero no tiene que ser formal (por ejemplo, para su propio contenido personal : "en mi sitio ...", "en mi blog ...", etc.). Ver: ¿Qué significa "buena" autopromoción? , algunos consejos y sugerencias sobre autopromoción , ¿Cuál es la definición exacta de "spam" para Stack Overflow? y Qué hace que algo sea spam .
Makyen
2

Sé que esta pregunta ha sido respondida, pero así es como hice que la mía funcione.

let ip = req.connection.remoteAddress.split(`:`).pop();
Lorem Ipsum
fuente
2

Si está bien con la biblioteca de terceros. Puede verificar request-ip .

Puedes usarlo es por

import requestIp from 'request-ip';

app.use(requestIp.mw())

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

El código fuente es bastante largo, así que no lo copiaré aquí, puedes consultarlo en https://github.com/pbojinov/request-ip/blob/master/src/index.js

Básicamente,

Busca encabezados específicos en la solicitud y recurre a algunos valores predeterminados si no existen.

La IP del usuario está determinada por el siguiente orden:

  1. X-Client-IP
  2. X-Forwarded-For (El encabezado puede devolver varias direcciones IP en el formato: "IP del cliente, proxy 1 IP, proxy 2 IP", por lo que tomamos la primera).
  3. CF-Connecting-IP (Destello de nube)
  4. Fastly-Client-Ip (Encabezado de alojamiento de CDN y Firebase rápidamente cuando se reenvía a una función en la nube)
  5. True-Client-Ip (Akamai y Cloudflare)
  6. X-Real-IP (Proxy Nginx / FastCGI)
  7. X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray)
  8. X-Forwarded, Forwarded-ForY Forwarded(variaciones de # 2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Si no se puede encontrar una dirección IP, regresará null.

Divulgar: no estoy asociado con la biblioteca.

Hongbo Miao
fuente
1

Esto funcionó para mí mejor que el resto. Mis sitios están detrás de CloudFlare y parecía requerirlo cf-connecting-ip.

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

No probé Express detrás de proxies ya que no dijo nada sobre este cf-connecting-ipencabezado.

ile
fuente
1

Con soporte de might-flare, nginx y 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;
    }
kakopappa
fuente
1

En mi caso, similar a esta solución, terminé usando el siguiente enfoque de x-forward-for :

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

x-forwarded-forEl encabezado seguirá agregando la ruta de la IP desde el origen hasta el servidor de destino final, por lo tanto, si necesita recuperar la IP del cliente de origen, este sería el primer elemento de la matriz.

Menelaos Kotsollaris
fuente
0

var ip = req.connection.remoteAddress;

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

Bhulawat Ajay
fuente
la salida es como: - :: ffff: XXX.XX.XX.XX de esto obtendremos ip
Bhulawat Ajay
3
Creo que ip = ip.split(':').pop();será difícil en este caso si la ip normal, es decir, 127.0.0.1 vendrá, todavía podrá darle ip.
9 de
0

El objeto de encabezado tiene todo lo que necesita, solo haga esto:

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

Poniendo todo junto con la solución witk @kakopappa más el morganregistro de la dirección IP del cliente:

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);
loretoparisi
fuente