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
2014年

如果您无法获得“ example.com”之类的req.hostname:stackoverflow.com/a/37824880/5333284
zhi.yang

Answers:


468

如果您是在像NGiNX这样的代理后面运行或只有什么,则应该检查“ x-forwarded-for”:

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

如果代理不是“您的”,那么我将不信任“ x-forward-for”标头,因为它可能是被欺骗的。


2
这是正确的,但是在我的情况下,我必须使用方括号(请参见上面的编辑),还要确保在nginx配置中启用了x-forward-for。奇迹般有效!
2013年

43
您需要记住,proxy_set_header X-Forwarded-For $remote_addr;如果您使用自己的反向代理,则必须将此指令放入您的nginx配置中。
Coxer 2015年

如果您打算在浏览器中使用IP,则http(s):// [ipv6]:port请注意[]是必需的,希望对您
有所

43
复制粘贴用户请注意:这可以返回用逗号分隔的IP地址列表。一个开发人员的错误将其复制并将其与IP进行比较。也许做一些类似的事情var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();来获得客户端IP。
戴维·琼斯

3
@Rishav :: 1是本地主机的IPv6地址
Daniel O

238

虽然从@alessioalex作品的回答,有作为另一种方式说明快递的背后代理的部分快递-指南

  1. 添加app.set('trust proxy', true)到您的明确初始化代码。
  2. 当您想获取远程客户端的IP时,请使用req.ipreq.ips以通常的方式使用(就像没有反向代理一样)

可选阅读:

  • 使用req.ipreq.ipsreq.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 2014年

1
在以IISnode作为代理的IIS后面,app.enable('trust proxy')也可以使用req.ip。除了我得到它的港口1.2.3.4:56789var ip = req.ip.split(':')[0]
简而言之

这个解决方案安全吗?
Daniel Kmak 2015年

3
我觉得这个答案缺乏安全性,需要更新。您应该始终定义应用程序信任的代理。接受的答案至少对欺骗有一点注意。也就是说,如果您使用的是Express,使用这样的库是一个更好的解决方案,但是引用的代码不正确并且在链接的资源上找不到。
菲尔(Phil)

54

nginx.conf文件中:
proxy_set_header X-Real-IP $remote_addr;

node.js服务器文件中:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

请注意,表达小写标头


3
欢迎使用Stack Overflow!而不是仅发布一段代码,请解释为什么这段代码可以解决所提出的问题。没有解释,这不是答案。
Artemix

1
@ququzone的答案还可以。解释是在名为“ x-real-ip”的请求上设置一个自定义标头,该标头使用来自访问者的原始IP地址。它适用于node和socket.io。
2013年

8
对我来说,req.headers['x-real-ip']即使在nginx.conf标头中用大写字母设置的IP地址也可用。
Nik Sumeiko 2014年

这就是为我解决的问题。即使将trust-proxy设置为true,它仍然使用本地127.0.0.1地址
David

30

特别是对于节点,事件连接下的http服务器组件的文档说:

[触发]当建立新的TCP流时。[the]套接字是net.Socket类型的对象。通常,用户将不希望访问此事件。特别是,由于协议解析器如何附加到套接字,套接字将不会发出可读事件。也可以通过访问套接字request.connection

因此,这意味着request.connection是一个套接字,根据文档,确实存在一个socket.remoteAddress属性,根据该文档,它是:

远程IP地址的字符串表示形式。例如,“ 74.125.127.100”或“ 2001:4860:a005 :: 68”。

在express下,请求对象也是Node http请求对象的实例,因此此方法仍然可以使用。

但是,在Express.js下,请求已具有两个属性:req.ipreq.ips

要求

返回远程地址,或启用“信任代理”时-上游地址。

要求

“信任代理”true,解析“X -转发,” IP地址列表,并返回一个数组,否则将返回一个空数组。例如,如果值是“ client,proxy1,proxy2”,您将收到数组[“ client”,“ proxy1”,“ proxy2”],其中“ proxy2”是最下游的。

值得一提的是,根据我的理解,Express req.ip是比更好的方法req.connection.remoteAddress,因为它req.ip包含实际的客户端ip(前提是在express中启用了受信任的代理),而另一个可能包含代理的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,您将可以通过以下方式访问您的node/ express应用程序路由中的ip: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
链接到您所关联的内容时,您必须在帖子中披露从属关系。如果您不透露从属关系,则将其视为垃圾邮件。披露必须是明确的,但不必是正式的(例如,对于您自己的个人内容:“在我的网站上”,“在我的博客上”等)。请参阅:什么表示“良好”的自我提升?自我推销一些提示和建议什么是“垃圾邮件”的堆栈溢出的确切定义是什么?,以及什么导致垃圾邮件
Makyen

2

我知道这个问题已经回答了,但是这就是我的工作方式。

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

2

如果您可以使用3rd-party库。您可以检查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,代理1 IP,代理2 IP”的格式返回多个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,Riverbed Stingray)
  8. X-ForwardedForwarded-ForForwarded(#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

没有测试Express是否在代理后面,因为它没有对此cf-connecting-ip头进行任何说明。


1

拥有可能的耀斑,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-forward-for方法:

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

x-forwarded-for标头将继续添加从起点到最终目标服务器的IP路由,因此,如果您需要检索起点客户端的IP,则这将是数组的第一项



0

标头对象具有您所需的一切,只需执行以下操作:

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

0

将所有@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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.