Express.js: як отримати віддалену адресу клієнта


256

Я не повністю розумію, як мені слід отримати IP-адресу віддаленого користувача.

Скажімо, у мене простий маршрут запиту, такий як:

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

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

Правильний вище підхід, щоб отримати реальну IP-адресу користувача чи є кращий спосіб? А як щодо проксі?


1
Як щодо використання node-ipware відповідно до пояснення тут .
un33k

якщо ви не можете отримати req.hostname як «example.com»: stackoverflow.com/a/37824880/5333284
zhi.yang

Відповіді:


469

Якщо ви працюєте за таким проксі-сервером, як NGiNX, або тим, що у вас є, лише тоді слід перевірити "x-forwarded-for":

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

Якщо проксі не "ваш", я б не довіряв заголовку "x-forwarded-for", оскільки він може бути підробленим.


2
Це правильно, проте в моїй ситуації мені довелося використовувати квадратні дужки (див. Вище редагувати) Також переконайтеся, що у вашій конфігурації nginx увімкнено x-forwarded-for. Працює як шарм!
дев'ятьсот

43
Потрібно пам’ятати, що ви повинні ввести цю директиву proxy_set_header X-Forwarded-For $remote_addr;у свою конфігурацію nginx, якщо ви використовуєте власний зворотний проксі.
Коксер

Якщо ви плануєте використовувати IP в браузері, тоді http (s): // [ipv6]: порт Помітьте, що [] потрібні, сподіваюся, це допоможе
psuhas

43
Користувачі копій-макаронів, зверніть увагу: Це може повернути розділений комою список IP-адрес. У нас виникла помилка від розробника, який копіював це і порівнював результат з IP-адресою. Можливо, зробіть щось на кшталт var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();отримання клієнтського IP.
Деві Джонс

3
@Rishav :: 1 - адреса IPv6 для localhost
Daniel O

238

Хоча відповідь від @alessioalex працює, є інший спосіб, як зазначено в розділі « Експрес» за розділом проксі-сервера експрес-посібника .

  1. Додайте app.set('trust proxy', true)до коду експрес-ініціалізації.
  2. Якщо ви хочете отримати ip віддаленого клієнта, використовуйте req.ipабо req.ipsзвичайним способом (як ніби немає зворотного проксі)

Необов’язкове читання:

  • Використовуйте req.ipабо req.ips. req.connection.remoteAddressне працює з цим рішенням.
  • Додаткові варіанти 'trust proxy'доступні, якщо вам потрібно щось більш складне, ніж довіряти всьому, що передається в x-forwarded-forзаголовку (наприклад, коли ваш проксі не видаляє попередньо існуючий заголовок x-forwarded-for з недовірених джерел). Докладнішу інформацію див. У пов'язаному посібнику.
  • Якщо ваш проксі-сервер не заповнений x-forwarded-forзаголовком, є дві можливості.
    1. Проксі-сервер не передає інформацію про те, де запит був спочатку. У цьому випадку не було б можливості з’ясувати, звідки походження запиту. Спочатку потрібно змінити конфігурацію проксі-сервера.
      • Наприклад, якщо ви використовуєте nginx як зворотний проксі, вам може знадобитися додати його proxy_set_header X-Forwarded-For $remote_addr;до конфігурації.
    2. Проксі-сервер ретранслює інформацію про те, звідки був запит у власний спосіб (наприклад, користувацьке заголовка http). У такому випадку ця відповідь не спрацює. Можливо, існує спеціальний спосіб отримати цю інформацію, але вам потрібно спершу зрозуміти механізм.

4
Моя відповідь була більш загальною (не прив’язана до Express), але якщо ви використовуєте Express, це справді кращий спосіб.
alessioalex

4
Ваш проксі-сервер повинен мати заголовок "x-forwarded-for" для віддаленої адреси. У випадку з nginx, наприклад, у своєму конфігураційному файлі у вас повинен бути proxy_set_header X-Forwarded-For $ remote_addr
Kamagatos

1
За межами IIS з IISnode як проксі, app.enable('trust proxy')теж працюєreq.ip . За винятком того, що я отримую порт із ним 1.2.3.4:56789. Щоб зняти це, я роблюvar ip = req.ip.split(':')[0]
Крістіан Вестербек

Чи безпечне це рішення?
Даніель Кмак

3
Я відчуваю, що ця відповідь не має безпеки та потребує оновлення. СТАЛИ Ви повинні визначити, які проксі-сервери довіряють вашій програмі. Прийнята відповідь хоча б трохи помітила про підробку. Однак це є кращим рішенням для використання такої бібліотеки, якщо ви використовуєте експрес, але кодований код невірний і не знайдений на пов'язаному ресурсі.
Філ

54

У nginx.confфайлі:
proxy_set_header X-Real-IP $remote_addr;

У node.jsфайлі сервера:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

зауважте, що виражайте заголовки нижнього регістру


3
Ласкаво просимо до переповнення стека! Замість того, щоб опублікувати лише блок коду, поясніть, чому саме цей код вирішує поставлену проблему. Без пояснення це не відповідь.
Артемікс

1
Відповідь @ququzone в порядку. Пояснення встановлюється користувацьким заголовком у запиті під назвою "x-real-ip", який бере початковий ip-адресу від відвідувача. Він працює для мене з вузлом і socket.io.
coffekid

8
Для мене IP-адреса доступна під заголовком req.headers['x-real-ip']навіть у nginx.confзаголовку з великими літерами.
Нік Сумейко

Це те, що вирішило це для мене. Навіть якщо довірчий проксі встановлено на істинне, він все ще використовував локальну адресу 127.0.0.1
Девід

30

Зокрема, для вузла, документація для компонента http-сервера під підключенням до події говорить:

[Спрацьовує], коли встановлено новий потік TCP. [Сокет] є об'єктом типу net.Socket. Зазвичай користувачі не захочуть отримувати доступ до цієї події. Зокрема, сокет не буде випромінювати почитаних подій через те, як аналізатор протоколу приєднується до сокета. До розетки можна також звернутися за адресою request.connection.

Отже, це означає, що request.connectionце socket, і згідно з документацією, дійсно є атрибут socket.remoteAddress, який згідно з документацією є:

Рядок представлення віддаленої IP-адреси. Наприклад, '74 .125.127.100 'або' 2001: 4860: a005 :: 68 '.

Під експресом об’єкт запиту також є екземпляром об’єкта запиту http Node, тому такий підхід все одно повинен працювати.

Однак у Express.js запит вже має два атрибути: req.ip та req.ips

req.ip

Поверніть віддалену адресу, або коли ввімкнено "довірений проксі" - адресу верхнього потоку.

req.ips

Коли "довірений проксі" є true, проаналізуйте ip-список "X-Forwarded-For" і поверніть масив, інакше повернеться порожній масив. Наприклад, якщо значенням було "client, proxy1, proxy2", ви отримаєте масив ["client", "proxy1", "proxy2"], де "proxy2" - це найдальший низхідний потік.

Можливо, варто згадати, що, наскільки я розумію, Експрес req.ip- це кращий підхід, ніж req.connection.remoteAddress, оскількиreq.ip містить фактичний ip клієнта (за умови, що довірений проксі включений у експресі), тоді як інший може містити IP-адресу проксі (якщо є один).

Ось чому причина прийнятої відповіді пропонує:

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

req.headers['x-forwarded-for']Буде еквівалентна експрес req.ip.



7

Це лише додаткова інформація для цієї відповіді .

Якщо ви використовуєте nginx, ви додали б proxy_set_header X-Real-IP $remote_addr;до блоку розташування сайту. /etc/nginx/sites-available/www.example.comнаприклад. Ось приклад блоку сервера.

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

Після перезапуску nginxви зможете отримати доступ до ip в маршрутах node/ expressдодаткахreq.headers['x-real-ip'] || req.connection.remoteAddress;


3

Як повідомляє Express за допомогою проксі , req.ipврахував зворотний проксі, якщо ви trust proxyправильно налаштували . Тому це краще, ніж те, req.connection.remoteAddressщо отримується з мережевого шару і не знає проксі.


3

Я для цього написав пакет. Ви можете використовувати його як експрес-програмне забезпечення. Мій пакет опублікований тут: https://www.npmjs.com/package/express-ip

Ви можете встановити модуль за допомогою

npm i express-ip

Використання

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
Ви повинні розкрити приналежність у публікації, посилаючись на те, з чим ви пов’язані. Якщо ви не розкриєте приналежність, це вважається спамом. Розкриття інформації повинно бути явним, але не повинно бути формальним (наприклад, для вашого власного особистого вмісту: "на моєму сайті ...", "в моєму блозі ..." тощо). Дивіться: Що означає "хороша" самореклама? , Деякі поради і рекомендації про саморекламу , Що таке точне визначення поняття «спам» для переповнення стека? , і Що робить щось спамом .
Макіен

2

Я знаю, що на це запитання відповіли, але ось як я змусив мене працювати.

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

2

Якщо ви все добре використовуєте сторонні бібліотеки. Ви можете перевірити request-ip .

Ви можете скористатися ним

import requestIp from 'request-ip';

app.use(requestIp.mw())

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

Вихідний код досить довгий, тому я тут не копіюю, ви можете перевірити на https://github.com/pbojinov/request-ip/blob/master/src/index.js

В основному,

Він шукає конкретні заголовки в запиті і повертається до деяких за замовчуванням, якщо вони не існують.

Користувач ip визначається наступним порядком:

  1. X-Client-IP
  2. X-Forwarded-For (Заголовок може повертати кілька IP-адрес у форматі: "клієнтський IP, проксі 1 IP, проксі 2 IP", тому ми беремо першу.)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip (Швидко заголовок хостингу CDN та Firebase, коли він передається хмарній функції)
  5. True-Client-Ip (Akamai та Cloudflare)
  6. X-Real-IP (Проксі-сервер Nginx / FastCGI)
  7. X-Cluster-Client-IP (Rackspace LB, русло річки Стингрей)
  8. X-Forwarded, Forwarded-Forта Forwarded(Варіації №2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Якщо IP-адресу неможливо знайти, вона повернеться null.

Розкриття: я не пов'язаний з бібліотекою.


1

Це працювало на мене краще, ніж на інших. Мої сайти стоять позаду CloudFlare, і, здавалося, цього потрібно cf-connecting-ip.

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

Не перевіряв Експрес на проксі, оскільки він нічого не говорив про цей cf-connecting-ipзаголовок.


1

З підтримкою Can-Flare, nginx та 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

У моєму випадку, подібне до цього рішення, я закінчив, використовуючи такий підхід x-forwarded-for :

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

x-forwarded-forзаголовок буде продовжувати додавати маршрут IP від ​​початкового коду до остаточного сервера призначення, таким чином, якщо вам потрібно отримати IP-адресу вихідного клієнта, це буде першим елементом масиву.


0

var ip = req.connection.remoteAddress;

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


ouput виглядає так: - :: ffff: XXX.XX.XX.XX з цього ми отримаємо ip
Bhulawat Ajay

3
Я думаю ip = ip.split(':').pop();, що в цьому випадку буде тісто, якщо прийде нормальний ip, тобто 127.0.0.1. Він все одно зможе дати вам ip.
9ме


0

З’єднання всіх разом з рішенням witk @kakopappa плюс morganреєстрація ip-адреси клієнта:

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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.