Express.js: comment obtenir une adresse client distante


256

Je ne comprends pas complètement comment obtenir une adresse IP d'utilisateur distant.

Disons que j'ai un itinéraire de demande simple tel que:

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

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

L'approche ci-dessus est-elle correcte pour obtenir la véritable adresse IP de l'utilisateur ou existe-t-il un meilleur moyen? Et qu'en est-il des procurations?


1
Que diriez-vous d'utiliser node-ipware selon l'explication ici .
un33k

si vous ne pouvez pas obtenir req.hostname comme 'example.com': stackoverflow.com/a/37824880/5333284
zhi.yang

Réponses:


469

Si vous courez derrière un proxy comme NGiNX ou quoi que ce soit, alors seulement, vous devriez vérifier «x-forwarded-for»:

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

Si le proxy n'est pas le vôtre, je ne ferais pas confiance à l'en-tête «x-forwarded-for», car il peut être usurpé.


2
C'est correct, cependant dans ma situation j'ai dû utiliser des crochets (voir ci-dessus modifier) ​​Assurez-vous également que x-forwarded-for est activé dans votre configuration nginx. Fonctionne comme un charme!
ninehundreds

43
Vous devez garder à l'esprit que vous devez mettre cette directive proxy_set_header X-Forwarded-For $remote_addr;dans votre configuration nginx au cas où vous utilisez votre propre proxy inverse.
Coxer

Si vous prévoyez d'utiliser l'IP dans le navigateur, alors http (s): // [ipv6]: port Notez que [] sont nécessaires, j'espère que cela vous aidera
psuhas

43
les utilisateurs de copy-pasta doivent noter: cela peut renvoyer une liste d'adresses IP séparées par des virgules. Nous avons eu un bug d'un développeur qui copiait cela et comparait le résultat à une IP. var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();Faites peut-être quelque chose comme obtenir l'adresse IP du client.
Davy Jones

3
@Rishav :: 1 est l'adresse IPv6 pour localhost
Daniel O

238

Bien que la réponse de @alessioalex fonctionne, il existe un autre moyen, comme indiqué dans la section Express derrière les proxys d' Express - guide .

  1. Ajoutez app.set('trust proxy', true)à votre code d'initialisation express.
  2. Lorsque vous souhaitez obtenir l'ip du client distant, utilisez req.ipou req.ipsde la manière habituelle (comme s'il n'y avait pas de proxy inverse)

Lecture facultative:

  • Utilisez req.ipou req.ips. req.connection.remoteAddressne fonctionne pas avec cette solution.
  • Plus d'options 'trust proxy'sont disponibles si vous avez besoin de quelque chose de plus sophistiqué que de faire confiance à tout ce qui est passé dans l'en- x-forwarded-fortête (par exemple, lorsque votre proxy ne supprime pas l'en-tête x-forwarded-for préexistant des sources non fiables). Voir le guide lié pour plus de détails.
  • Si votre serveur proxy ne remplit pas l'en- x-forwarded-fortête, il y a deux possibilités.
    1. Le serveur proxy ne transmet pas les informations sur l'origine de la demande. Dans ce cas, il n'y aurait aucun moyen de savoir d'où venait la demande. Vous devez d'abord modifier la configuration du serveur proxy.
      • Par exemple, si vous utilisez nginx comme proxy inverse, vous devrez peut-être ajouter proxy_set_header X-Forwarded-For $remote_addr;à votre configuration.
    2. Le serveur proxy relaie les informations sur l'origine de la demande de manière propriétaire (par exemple, un en-tête http personnalisé). Dans ce cas, cette réponse ne fonctionnerait pas. Il existe peut-être un moyen personnalisé de diffuser ces informations, mais vous devez d'abord comprendre le mécanisme.

4
Ma réponse était plus générale (pas liée à Express), mais si vous utilisez Express, c'est en effet la meilleure façon.
alessioalex

4
Votre serveur proxy doit avoir l'en-tête «x-forwarded-for» défini sur l'adresse distante. Dans le cas de nginx par exemple, vous devriez avoir proxy_set_header X-Forwarded-For $ remote_addr dans votre fichier de configuration
Kamagatos

1
Derrière IIS avec IISnode comme proxy, app.enable('trust proxy')fonctionne aussi à utiliser req.ip. Sauf que j'obtiens le port avec 1.2.3.4:56789. Pour retirer cela, je le faisvar ip = req.ip.split(':')[0]
Christiaan Westerbeek

Cette solution est-elle sûre?
Daniel Kmak

3
Je pense que cette réponse manque de sécurité et doit être mise à jour. Vous devez TOUJOURS définir les procurations approuvées par votre application. La réponse acceptée a au moins un petit avis sur l'usurpation d'identité. Cela dit, c'est une meilleure solution pour utiliser une bibliothèque comme celle-ci si vous utilisez express, mais le code cité est incorrect et ne se trouve pas sur la ressource liée.
Phil

54

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

Dans node.jsle fichier serveur:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

notez que les en-têtes minuscules express


3
Bienvenue dans Stack Overflow! Plutôt que de publier uniquement un bloc de code, veuillez expliquer pourquoi ce code résout le problème posé. Sans explication, ce n'est pas une réponse.
Artemix

1
La réponse de @ququzone est correcte. L'explication est définie un en-tête personnalisé sur la demande nommée "x-real-ip" qui prend l'adresse IP d'origine du visiteur. Cela fonctionne pour moi avec node et socket.io.
coffekid

8
Pour moi, l'adresse IP est disponible sous req.headers['x-real-ip']même dans l'en- nginx.conftête est définie avec des lettres majuscules.
Nik Sumeiko

C'est ce qui l'a résolu pour moi. Même avec trust-proxy défini sur true, il utilisait toujours l'adresse locale 127.0.0.1
David

30

En particulier pour le nœud, la documentation du composant serveur http, sous connexion d'événement, indique:

[Déclenché] lorsqu'un nouveau flux TCP est établi. [Le] socket est un objet de type net.Socket. Habituellement, les utilisateurs ne voudront pas accéder à cet événement. En particulier, le socket n'émettra pas d'événements lisibles en raison de la façon dont l'analyseur de protocole se connecte au socket. La prise est également accessible à request.connection.

Donc, cela signifie qu'il request.connections'agit d'un socket et selon la documentation, il y a en effet un attribut socket.remoteAddress qui, selon la documentation, est:

La représentation sous forme de chaîne de l'adresse IP distante. Par exemple, '74 .125.127.100 'ou' 2001: 4860: a005 :: 68 '.

Sous express, l'objet de requête est également une instance de l'objet de requête Node http, donc cette approche devrait toujours fonctionner.

Cependant, sous Express.js, la demande a déjà deux attributs: req.ip et req.ips

req.ip

Renvoyez l'adresse distante, ou lorsque "proxy de confiance" est activé - l'adresse en amont.

req.ips

Lorsque "proxy de confiance" est true, analyser la liste d'adresses IP "X-Forwarded-For" et retourner un tableau, sinon un tableau vide est retourné. Par exemple, si la valeur était "client, proxy1, proxy2", vous recevrez le tableau ["client", "proxy1", "proxy2"] où "proxy2" est le plus en aval.

Il convient de mentionner que, selon moi, l'Express req.ipest une meilleure approche que req.connection.remoteAddress, puisquereq.ip contient l'IP du client réel (à condition que le proxy de confiance soit activé dans express), tandis que l'autre peut contenir l'adresse IP du proxy (s'il y a une).

C'est la raison pour laquelle la réponse actuellement acceptée suggère:

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

Le req.headers['x-forwarded-for']sera l'équivalent d'express req.ip.



7

Ce ne sont que des informations supplémentaires pour cette réponse .

Si vous utilisez nginx, vous ajouteriez proxy_set_header X-Real-IP $remote_addr;au bloc d'emplacement du site. /etc/nginx/sites-available/www.example.compar exemple. Voici un exemple de bloc serveur.

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

Après le redémarrage nginx, vous pourrez accéder à l'ip dans vos routes node/ expressapplication avecreq.headers['x-real-ip'] || req.connection.remoteAddress;


3

Selon Express derrière les proxys , req.ipa pris en compte le proxy inverse si vous l'avez configuré trust proxycorrectement. Par conséquent, il vaut mieux que req.connection.remoteAddressce qui est obtenu à partir de la couche réseau et ignore le proxy.


3

J'ai écrit un paquet à cet effet. Vous pouvez l'utiliser comme middleware express. Mon package est publié ici: https://www.npmjs.com/package/express-ip

Vous pouvez installer le module en utilisant

npm i express-ip

Usage

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
Vous devez divulguer votre affiliation dans le message lorsque vous créez un lien vers quelque chose auquel vous êtes affilié. Si vous ne divulguez pas d'affiliation, cela est considéré comme du spam. La divulgation doit être explicite, mais n'a pas besoin d'être formelle (par exemple pour votre propre contenu personnel : "sur mon site ...", "sur mon blog ...", etc.). Voir: Qu'est - ce qui signifie une "bonne" promotion personnelle? , quelques astuces et conseils sur l'autopromotion , Quelle est la définition exacte du "spam" pour Stack Overflow? et ce qui fait du spam .
Makyen

2

Je sais qu'on a répondu à cette question, mais voici comment j'ai fait travailler la mienne.

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

2

Si vous êtes bien en utilisant une bibliothèque tierce. Vous pouvez vérifier request-ip .

Vous pouvez l'utiliser c'est par

import requestIp from 'request-ip';

app.use(requestIp.mw())

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

Le code source est assez long, donc je ne copierai pas ici, vous pouvez vérifier à https://github.com/pbojinov/request-ip/blob/master/src/index.js

Fondamentalement,

Il recherche des en-têtes spécifiques dans la demande et revient à certains paramètres par défaut s'ils n'existent pas.

L'IP utilisateur est déterminé par l'ordre suivant:

  1. X-Client-IP
  2. X-Forwarded-For (L'en-tête peut renvoyer plusieurs adresses IP au format: "IP client, proxy 1 IP, proxy 2 IP", nous prenons donc la première.)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip (En-tête d'hébergement CDN et Firebase rapide en cas de transfert vers une fonction cloud)
  5. True-Client-Ip (Akamai et Cloudflare)
  6. X-Real-IP (Proxy Nginx / FastCGI)
  7. X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray)
  8. X-Forwarded, Forwarded-ForEt Forwarded(Variations de n ° 2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Si une adresse IP est introuvable, elle reviendra null.

Divulgation: je ne suis pas associé à la bibliothèque.


1

Cela a fonctionné pour moi mieux que les autres. Mes sites sont derrière CloudFlare et cela semblait nécessiter cf-connecting-ip.

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

N'a pas testé Express derrière les procurations car il ne disait rien sur cet en- cf-connecting-iptête.


1

Avec prise en charge de pourrait-flare, nginx et 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

Dans mon cas, similaire à cette solution, j'ai fini par utiliser l' approche x-forwarded-for suivante :

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

x-forwarded-forL'en-tête continuera d'ajouter l'itinéraire de l'IP de l'origine jusqu'au serveur de destination finale, donc si vous avez besoin de récupérer l'IP du client d'origine, ce serait le premier élément du tableau.


0

var ip = req.connection.remoteAddress;

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


ouput est comme: - :: ffff: XXX.XX.XX.XX à partir de cela, nous aurons ip
Bhulawat Ajay

3
Je pense que ce ip = ip.split(':').pop();sera la pâte dans ce cas si l'ip normale, c'est-à-dire 127.0.0.1 viendra, il sera toujours en mesure de vous donner l'ip.
9me

0

L'objet headers a tout ce dont vous avez besoin, procédez comme suit:

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

0

Assemblage de la solution witk @kakopappa et de la morganjournalisation de l'adresse IP du 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);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.