Express.js: cara mendapatkan alamat klien jarak jauh

256

Saya tidak sepenuhnya mengerti bagaimana saya harus mendapatkan alamat IP pengguna jarak jauh.

Katakanlah saya memiliki rute permintaan sederhana seperti:

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

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

Apakah pendekatan di atas benar untuk mendapatkan alamat IP pengguna yang sebenarnya atau apakah ada cara yang lebih baik? Dan bagaimana dengan proxy?

Erik
sumber
1
Bagaimana dengan menggunakan node-ipware sesuai penjelasan di sini .
un33k
jika Anda tidak bisa mendapatkan req.hostname seperti 'example.com': stackoverflow.com/a/37824880/5333284
zhi.yang
1
Kemungkinan duplikat dari Cara menentukan alamat IP pengguna di simpul
Dan Dascalescu

Jawaban:

469

Jika Anda menjalankan di belakang proxy seperti NGiNX atau apa pun yang Anda miliki, hanya dengan demikian Anda harus memeriksa 'x-forwarded-for':

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

Jika proksi tersebut bukan 'milikmu', saya tidak akan mempercayai tajuk 'x-forwarded-for', karena dapat dipalsukan.

alessioalex
sumber
2
Ini benar, namun dalam situasi saya, saya harus menggunakan tanda kurung siku (lihat edit di atas) Juga pastikan Anda memiliki x-penerusan-untuk diaktifkan di konfigurasi nginx Anda. Bekerja seperti pesona!
sembilan ratus empat
43
Anda harus ingat bahwa Anda harus meletakkan direktif ini proxy_set_header X-Forwarded-For $remote_addr;ke dalam konfigurasi nginx Anda jika Anda menggunakan proxy terbalik Anda sendiri.
Coxer
Jika Anda berencana untuk menggunakan IP di browser maka http (s): // [ipv6]: port Perhatikan [] diperlukan, harap ini membantu
psuhas
43
harap dicatat: pengguna copy-pasta dapat mengembalikan daftar alamat IP yang dipisahkan koma. Kami memiliki bug dari pengembang yang menyalin ini dan membandingkan hasilnya dengan IP. Mungkin melakukan sesuatu seperti var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();mendapatkan IP klien.
Davy Jones
3
@Rishav :: 1 adalah alamat IPv6 untuk localhost
Daniel O
238

Sementara jawaban dari karya @alessioalex, ada cara lain sebagaimana tercantum dalam Ekspres belakang proxy bagian dari Express - panduan .

  1. Tambahkan app.set('trust proxy', true)ke kode inisialisasi ekspres Anda.
  2. Ketika Anda ingin mendapatkan ip klien jarak jauh, gunakan req.ipatau req.ipsdengan cara biasa (seolah-olah tidak ada proxy terbalik)

Bacaan opsional:

  • Gunakan req.ipatau req.ips. req.connection.remoteAddresstidak bekerja dengan solusi ini.
  • Lebih banyak opsi 'trust proxy'tersedia jika Anda membutuhkan sesuatu yang lebih canggih daripada memercayai semua yang dilewati di x-forwarded-forheader (misalnya, ketika proxy Anda tidak menghapus header x-forwarded-for-existing yang sudah ada dari sumber yang tidak terpercaya). Lihat panduan tertaut untuk detail lebih lanjut.
  • Jika server proxy Anda tidak memiliki x-forwarded-fortajuk, ada dua kemungkinan.
    1. Server proxy tidak menyampaikan informasi di mana permintaan itu awalnya. Dalam hal ini, tidak akan ada cara untuk mengetahui dari mana asal permintaan tersebut. Anda harus memodifikasi konfigurasi server proxy terlebih dahulu.
      • Misalnya, jika Anda menggunakan nginx sebagai proxy terbalik, Anda mungkin perlu menambahkan proxy_set_header X-Forwarded-For $remote_addr;konfigurasi Anda.
    2. Server proksi menyampaikan informasi dari mana asal permintaan secara eksklusif (misalnya, header http khusus). Dalam hal demikian, jawaban ini tidak akan berfungsi. Mungkin ada cara khusus untuk mengeluarkan informasi itu, tetapi Anda harus terlebih dahulu memahami mekanismenya.
Haozhun
sumber
4
Jawaban saya lebih umum (tidak terkait dengan Express), tetapi jika Anda menggunakan Express itu memang cara yang lebih baik.
alessioalex
4
Server proxy Anda harus mengatur tajuk 'x-diteruskan-untuk' ke alamat jarak jauh. Dalam kasus nginx misalnya, Anda harus memiliki proxy_set_header X-Forwarded-For $ remote_addr dalam file konfigurasi Anda
Kamagatos
1
Di belakang IIS dengan IISnode sebagai proxy, app.enable('trust proxy')berfungsi juga untuk digunakan req.ip. Kecuali saya mendapatkan port dengan itu 1.2.3.4:56789. Untuk menghapus itu, saya lakukanvar ip = req.ip.split(':')[0]
Christiaan Westerbeek
Apakah solusi ini aman?
Daniel Kmak
3
Saya merasa bahwa jawaban ini kurang aman dan perlu diperbarui. Anda harus SELALU mendefinisikan proxy yang dipercayai aplikasi Anda. Jawaban yang diterima setidaknya memiliki sedikit pemberitahuan tentang spoofing. Yang mengatakan, itu ADALAH solusi yang lebih baik untuk menggunakan perpustakaan seperti ini jika Anda menggunakan express, tetapi kode yang dikutip salah dan tidak ditemukan pada sumber daya tertaut.
Phil
54

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

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

perhatikan bahwa tajuk huruf kecil express

ququzone
sumber
3
Selamat Datang di Stack Overflow! Daripada hanya memposting blok kode, tolong jelaskan mengapa kode ini menyelesaikan masalah yang ditimbulkan. Tanpa penjelasan, ini bukan jawaban.
Artemix
1
@ququzone jawaban ok. Penjelasannya adalah mengatur header kustom pada permintaan bernama "x-real-ip" yang mengambil alamat ip asli dari pengunjung. Ini berfungsi untuk saya dengan node dan socket.io.
coffekid
8
Bagi saya, alamat IP tersedia req.headers['x-real-ip']bahkan di bawah nginx.confheader diatur dengan huruf kapital.
Nik Sumeiko
Inilah yang memecahkannya untuk saya. Bahkan dengan kepercayaan-proxy disetel ke true, itu masih menggunakan alamat 127.0.0.1 lokal
David
30

Khusus untuk node, dokumentasi untuk komponen server http, di bawah koneksi acara mengatakan:

[Dipicu] ketika aliran TCP baru dibuat. Soket [adalah] objek dengan tipe net. Socket. Biasanya pengguna tidak ingin mengakses acara ini. Secara khusus, soket tidak akan memancarkan peristiwa yang dapat dibaca karena cara pengurai protokol menempel ke soket. Soket juga dapat diakses di request.connection.

Jadi, itu artinya request.connectionsoket dan menurut dokumentasi memang ada atribut socket.remoteAddress yang menurut dokumentasi adalah:

Representasi string dari alamat IP jarak jauh. Misalnya, '74 .125.127.100 'atau' 2001: 4860: a005 :: 68 '.

Di bawah express, objek permintaan juga merupakan instance dari objek permintaan Node http, jadi pendekatan ini harus tetap berfungsi.

Namun, di bawah Express.js permintaan sudah memiliki dua atribut: req.ip dan req.ips

req.ip

Kembalikan alamat jarak jauh, atau ketika "trust trust" diaktifkan - alamat hulu.

req.ips

Ketika "trust proxy" adalah true, parsing daftar alamat "X-Forwarded-For" dan kembalikan array, jika tidak, array kosong akan dikembalikan. Sebagai contoh jika nilainya "klien, proxy1, proxy2" Anda akan menerima array ["klien", "proxy1", "proxy2"] di mana "proxy2" adalah down-stream terjauh.

Mungkin perlu disebutkan bahwa, menurut pemahaman saya, Ekspres req.ipadalah pendekatan yang lebih baik daripada req.connection.remoteAddress, karena req.ipberisi ip klien yang sebenarnya (asalkan proksi tepercaya diaktifkan secara ekspres), sedangkan yang lain mungkin berisi alamat IP proksi (jika ada satu).

Itulah alasan mengapa jawaban yang diterima saat ini menyarankan:

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

Ini req.headers['x-forwarded-for']akan menjadi setara dengan express req.ip.

Edwin Dalorzo
sumber
11
  1. Menambahkan app.set('trust proxy', true)
  2. Gunakan req.ipatau req.ipsdengan cara biasa
Botak
sumber
2
Ini cara untuk pergi. Lihat expressjs.com/en/guide/behind-proxies.html untuk detailnya.
O. Jones
Sangat mudah dan ringkas. Suka jawaban yang sederhana.
gilbert-v
7

Ini hanya informasi tambahan untuk jawaban ini .

Jika Anda menggunakan nginx, Anda akan menambah proxy_set_header X-Real-IP $remote_addr;blok lokasi untuk situs tersebut. /etc/nginx/sites-available/www.example.comsebagai contoh. Berikut adalah contoh blok 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;
    }
}

Setelah memulai ulang nginx, Anda akan dapat mengakses ip di rute node/ expressaplikasi Anda denganreq.headers['x-real-ip'] || req.connection.remoteAddress;

belajarsemore lagi
sumber
3

Menurut Express di belakang proksi , req.iptelah mempertimbangkan proksi terbalik akun jika Anda telah mengonfigurasi trust proxydengan benar. Oleh karena itu lebih baik daripada req.connection.remoteAddressyang diperoleh dari lapisan jaringan dan tidak mengetahui proxy.

abbr
sumber
3

Saya menulis paket untuk tujuan itu. Anda dapat menggunakannya sebagai middleware ekspres. Paket saya diterbitkan di sini: https://www.npmjs.com/package/express-ip

Anda dapat menginstal modul menggunakan

npm i express-ip

Pemakaian

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
sumber
1
Anda harus mengungkapkan afiliasi dalam pos ketika menautkan ke sesuatu yang Anda berafiliasi. Jika Anda tidak mengungkapkan afiliasi, itu dianggap sebagai spam. Pengungkapan harus eksplisit, tetapi tidak perlu formal (mis. Untuk konten pribadi Anda : "di situs saya ...", "di blog saya ...", dll.). Lihat: Apa yang menandakan promosi diri "Bagus"? , beberapa tips dan saran tentang promosi diri , Apa definisi yang tepat dari "spam" untuk Stack Overflow? , dan Apa yang membuat sesuatu menjadi spam .
Makyen
2

Saya tahu pertanyaan ini telah dijawab, tetapi beginilah cara saya mengerjakannya.

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

Jika Anda baik-baik saja menggunakan perpustakaan pihak ke-3. Anda dapat memeriksa permintaan-ip .

Anda dapat menggunakannya dengan

import requestIp from 'request-ip';

app.use(requestIp.mw())

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

Kode sumbernya cukup panjang, jadi saya tidak akan menyalin di sini, Anda dapat memeriksa di https://github.com/pbojinov/request-ip/blob/master/src/index.js

Pada dasarnya,

Itu mencari header spesifik dalam permintaan dan kembali ke beberapa default jika mereka tidak ada.

IP pengguna ditentukan oleh urutan berikut:

  1. X-Client-IP
  2. X-Forwarded-For (Header dapat mengembalikan beberapa alamat IP dalam format: "IP klien, IP proxy 1, IP proxy 2", jadi kami mengambil yang pertama.)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip (Header CDN dan hosting Firebase yang cepat ketika dibagikan ke fungsi cloud)
  5. True-Client-Ip (Akamai dan Cloudflare)
  6. X-Real-IP (Nginx proxy / FastCGI)
  7. X-Cluster-Client-IP (Rackspace LB, Stingray Riverbed)
  8. X-Forwarded, Forwarded-Fordan Forwarded(Variasi # 2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Jika alamat IP tidak dapat ditemukan, itu akan kembali null.

Diungkapkan: Saya tidak terkait dengan perpustakaan.

Hongbo Miao
sumber
1

Ini bekerja untuk saya lebih baik daripada yang lain. Situs saya ada di belakang CloudFlare dan sepertinya diperlukan cf-connecting-ip.

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

Tidak menguji Express di belakang proxy karena tidak mengatakan apa-apa tentang cf-connecting-ipheader ini .

ile
sumber
1

Dengan dukungan can-suar, nginx dan 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
sumber
1

Dalam kasus saya, mirip dengan solusi ini , saya akhirnya menggunakan pendekatan x-forwarded-for berikut :

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

x-forwarded-forheader akan terus menambahkan rute IP dari asal sampai ke server tujuan akhir, jadi jika Anda perlu mengambil IP klien asal, ini akan menjadi item pertama dari array.

Menelaos Kotsollaris
sumber
0

var ip = req.connection.remoteAddress;

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

Bhulawat Ajay
sumber
ouput seperti: - :: ffff: XXX.XX.XX.XX dari ini kita akan mendapatkan ip
Bhulawat Ajay
3
Saya pikir ip = ip.split(':').pop();akan menjadi adonan dalam hal ini jika ip normal yaitu 127.0.0.1 akan datang Ini masih akan dapat memberi Anda ip.
9me
0

Objek header memiliki semua yang Anda butuhkan, lakukan saja ini:

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

Menyatukan semua solusi witk @kakopappa plus morganlogging dari alamat ip klien:

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
sumber