Express.js: como obter o endereço do cliente remoto

256

Não entendo completamente como devo obter um endereço IP de usuário remoto.

Digamos que eu tenha uma rota de solicitação simples, como:

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

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

A abordagem acima está correta para obter o endereço IP real do usuário ou existe uma maneira melhor? E os proxies?

Erik
fonte
1
Que tal usar o node-ipware de acordo com a explicação aqui .
un33k
se você não pode obter o req.hostname como 'example.com': stackoverflow.com/a/37824880/5333284
zhi.yang
1
Possível duplicata Como determinar o endereço IP de um usuário no nó
Dan Dascalescu

Respostas:

469

Se você estiver executando atrás de um proxy como o NGiNX ou o que você tem, somente então você deve procurar por 'x-forwarded-for':

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

Se o proxy não for 'seu', eu não confiaria no cabeçalho 'x-forwarded-for', porque ele pode ser falsificado.

alessioalex
fonte
2
Isso está correto, no entanto, na minha situação, tive que usar colchetes (veja a edição acima). Verifique também se o x-forwarded-enabled está ativado na configuração do nginx. Funciona como um encanto!
Nonhundreds
43
Você precisa ter em mente que você deve colocar esta diretiva proxy_set_header X-Forwarded-For $remote_addr;na sua configuração nginx, caso esteja usando seu próprio proxy reverso.
Coxer
Se você pretende usar o IP no navegador, em seguida, HTTP (S): // [IPv6]: porta Observe o [] são necessários, espero que isso ajude
psuhas
43
usuários de copiar-massas, observe: Isso pode retornar uma lista separada por vírgula de endereços IP. Tivemos um erro de um desenvolvedor copiando isso e comparando o resultado com um IP. Talvez faça algo como var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();obter o IP do cliente.
Davy Jones
3
@Rishav :: 1 é o endereço IPv6 para localhost
Daniel O
238

Enquanto a resposta do @alessioalex funciona, há outra maneira, conforme indicado na seção Express behind proxies do Express - guide .

  1. Adicione app.set('trust proxy', true)ao seu código de inicialização expressa.
  2. Quando você deseja obter o ip do cliente remoto, use req.ipou req.ipsda maneira usual (como se não houvesse um proxy reverso)

Leitura opcional:

  • Use req.ipou req.ips. req.connection.remoteAddressnão funciona com esta solução.
  • 'trust proxy'Estão disponíveis mais opções se você precisar de algo mais sofisticado do que confiar em tudo o que é passado no x-forwarded-forcabeçalho (por exemplo, quando o seu proxy não remove o cabeçalho x-forwarded-for preexistente de fontes não confiáveis). Consulte o guia vinculado para mais detalhes.
  • Se o servidor proxy não preencher o x-forwarded-forcabeçalho, há duas possibilidades.
    1. O servidor proxy não retransmite as informações de onde a solicitação estava originalmente. Nesse caso, não haveria maneira de descobrir de onde a solicitação era originalmente. Você precisa modificar a configuração do servidor proxy primeiro.
      • Por exemplo, se você usar o nginx como seu proxy reverso, poderá ser necessário adicionar proxy_set_header X-Forwarded-For $remote_addr;à sua configuração.
    2. O servidor proxy retransmite as informações de onde a solicitação era originalmente de maneira proprietária (por exemplo, cabeçalho http personalizado). Nesse caso, essa resposta não funcionaria. Pode haver uma maneira personalizada de divulgar essas informações, mas você precisa primeiro entender o mecanismo.
Haozhun
fonte
4
Minha resposta foi mais geral (não ligada ao Express), mas se você estiver usando o Express, esse é realmente o melhor caminho.
Alessioalex 30/05
4
Seu servidor proxy deve ter o cabeçalho 'x-forwarded-for' definido no endereço remoto. No caso do nginx por exemplo, você deve ter proxy_set_header X-Forwarded-For $ remote_addr em seu arquivo de configuração
Kamagatos
1
Por trás do IIS com o IISnode como proxy, app.enable('trust proxy')também funciona para uso req.ip. Exceto que eu recebo a porta com ela 1.2.3.4:56789. Para tirar isso, eu façovar ip = req.ip.split(':')[0]
Christiaan Westerbeek
Esta solução é segura?
Daniel Kmak
3
Sinto que esta resposta carece de segurança e precisa ser atualizada. SEMPRE defina em quais proxies seu aplicativo confia. A resposta aceita, pelo menos, tem um pequeno aviso sobre falsificação. Dito isto, é uma solução melhor usar uma biblioteca como esta se você estiver usando express, mas o código citado está incorreto e não é encontrado no recurso vinculado.
Phil
54

No nginx.confarquivo:
proxy_set_header X-Real-IP $remote_addr;

No node.jsarquivo do servidor:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

note que expressam cabeçalhos em minúsculas

ququzone
fonte
3
Bem-vindo ao Stack Overflow! Em vez de publicar apenas um bloco de código, explique por que esse código resolve o problema apresentado. Sem uma explicação, isso não é uma resposta.
Artemix
1
A resposta de @ququzone está ok. A explicação é definir um cabeçalho personalizado na solicitação denominada "x-real-ip", que recebe o endereço IP original do visitante. Funciona para mim com o node e o socket.io.
coffekid
8
Para mim, o endereço IP está disponível em req.headers['x-real-ip']até no nginx.confcabeçalho definido com letras maiúsculas.
Nikon Sumeiko
Foi isso que resolveu para mim. Mesmo com o conjunto de confiança-proxy a verdade, ainda estava usando o endereço local 127.0.0.1
David
30

Especialmente para o nó, a documentação para o componente do servidor http, em conexão de evento, diz:

[Disparado] quando um novo fluxo TCP é estabelecido. [O] soquete é um objeto do tipo net.Socket. Normalmente, os usuários não desejam acessar este evento. Em particular, o soquete não emitirá eventos legíveis devido à maneira como o analisador de protocolo é anexado ao soquete. O soquete também pode ser acessado em request.connection.

Então, isso significa request.connection é um soquete e, de acordo com a documentação, existe realmente um atributo socket.remoteAddress que, de acordo com a documentação, é:

A representação em cadeia do endereço IP remoto. Por exemplo, '74 .125.127.100 'ou' 2001: 4860: a005 :: 68 '.

Sob express, o objeto de solicitação também é uma instância do objeto de solicitação http do Nó, portanto essa abordagem ainda deve funcionar.

No entanto, no Express.js, a solicitação já possui dois atributos: req.ip e req.ips

req.ip

Retorne o endereço remoto ou quando o "proxy de confiança" estiver ativado - o endereço upstream.

req.ips

Quando "trust proxy" for true, analise a lista de endereços IP "X-Forwarded-For" e retorne uma matriz, caso contrário, uma matriz vazia será retornada. Por exemplo, se o valor fosse "cliente, proxy1, proxy2", você receberia a matriz ["cliente", "proxy1", "proxy2"] em que "proxy2" é o mais a jusante.

Vale ressaltar que, no meu entender, o Express req.ipé uma abordagem melhor do que req.connection.remoteAddress, uma vez quereq.ip contém o IP do cliente real (desde que o proxy confiável seja ativado no express), enquanto o outro pode conter o endereço IP do proxy (se houver 1).

Essa é a razão pela qual a resposta atualmente aceita sugere:

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

O req.headers['x-forwarded-for']será o equivalente a express req.ip.

Edwin Dalorzo
fonte
11
  1. Adicionar app.set('trust proxy', true)
  2. Use req.ipou req.ipsda maneira usual
Careca
fonte
2
Este é o caminho a percorrer. Consulte expressjs.com/en/guide/behind-proxies.html para obter detalhes.
O. Jones
Tão fácil e conciso. Ame uma resposta simples.
Gilbert-v
7

Esta é apenas uma informação adicional para esta resposta .

Se você estiver usando nginx, você adicionaria proxy_set_header X-Real-IP $remote_addr;ao bloco de localização do site. /etc/nginx/sites-available/www.example.compor exemplo. Aqui está um exemplo de bloco 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;
    }
}

Após reiniciar nginx, você poderá acessar o ip em suas rotas node/ expressaplicação comreq.headers['x-real-ip'] || req.connection.remoteAddress;

learnsomemore
fonte
3

De acordo com o Express behind proxy , req.ipconsiderou o proxy reverso se você configurou trust proxycorretamente. Portanto, é melhor do req.connection.remoteAddressque o obtido na camada de rede e desconhece o proxy.

abbr
fonte
3

Eu escrevi um pacote para esse fim. Você pode usá-lo como middleware expresso. Meu pacote está publicado aqui: https://www.npmjs.com/package/express-ip

Você pode instalar o 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
fonte
1
Você deve divulgar a afiliação na postagem ao vincular a algo ao qual está afiliado. Se você não divulgar a afiliação, ela será considerada spam. A divulgação deve ser explícita, mas não precisa ser formal (por exemplo, para seu próprio conteúdo pessoal : "no meu site ...", "no meu blog ..." etc.). Veja: O que significa "boa" autopromoção? , algumas dicas e conselhos sobre autopromoção . Qual é a definição exata de "spam" para Stack Overflow? e O que faz com que algo seja spam .
Makyen 30/03
2

Sei que esta pergunta foi respondida, mas aqui está como consegui que a minha funcionasse.

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

Se você estiver bem usando a biblioteca de terceiros. Você pode verificar request-ip .

Você pode usá-lo é por

import requestIp from 'request-ip';

app.use(requestIp.mw())

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

O código fonte é bastante longo, então não copio aqui. Você pode conferir em https://github.com/pbojinov/request-ip/blob/master/src/index.js

Basicamente,

Ele procura por cabeçalhos específicos na solicitação e retorna a alguns padrões se eles não existirem.

O IP do usuário é determinado pela seguinte ordem:

  1. X-Client-IP
  2. X-Forwarded-For (O cabeçalho pode retornar vários endereços IP no formato: "IP do cliente, IP do proxy 1, IP do proxy 2", portanto, escolhemos o primeiro.)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip (Rapidamente CDN e Firebase hospedagem cabeçalho quando forwared para uma função de nuvem)
  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(Variações de # 2)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

Se um endereço IP não puder ser encontrado, ele retornará null.

Divulgue: Eu não estou associado à biblioteca.

Hongbo Miao
fonte
1

Isso funcionou para mim melhor do que o resto. Meus sites estão por trás do CloudFlare e parecia exigir cf-connecting-ip.

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

Não testou o Express atrás de proxies , pois não dizia nada sobre esse cf-connecting-ipcabeçalho.

ile
fonte
1

Com suporte a 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;
    }
kakopappa
fonte
1

No meu caso, semelhante a esta solução, acabei usando a seguinte abordagem x-forwarded-for :

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

x-forwarded-forO cabeçalho continuará adicionando a rota do IP desde a origem até o servidor de destino final; portanto, se você precisar recuperar o IP do cliente de origem, esse seria o primeiro item da matriz.

Menelaos Kotsollaris
fonte
0

var ip = req.connection.remoteAddress;

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

Bhulawat Ajay
fonte
ouput é como: - :: ffff: XXX.XX.XX.XX a partir disso, obteremos o ip #
Bhulawat Ajay
3
Eu acho que ip = ip.split(':').pop();vai ser massa neste caso, se o ip normal ou seja, 127.0.0.1 virá. Ainda será capaz de lhe dar ip.
9me
0

O objeto cabeçalhos tem tudo o que você precisa, basta fazer o seguinte:

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

Juntando tudo a solução witk @kakopappa mais o morganlog do endereço IP do 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
fonte