js:如何获取远程客户端地址

我不完全明白我应该如何获得一个远程用户IP地址。

假设我有一个简单的请求路由,如:

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


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

上述方法是否正确,以获得真实的用户IP地址或有更好的方法? 那么代理呢?< / p >

435400 次浏览

如果你运行在一个像NGiNX之类的代理之后,那么你应该检查'x-forwarded-for':

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

如果代理不是“你的”,我不会相信'x-forwarded-for'标头,因为它可以被欺骗。

虽然来自@alessioalex的答案是有效的,但还有另一种方法,如快捷指南代理背后的表达部分所述。

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

可选的阅读:

  • 使用req.ipreq.ipsreq.connection.remoteAddress不适用于此解决方案。
  • 如果你需要一些比信任x-forwarded-for报头中传递的所有内容更复杂的东西(例如,当你的代理没有从不可信的源中删除预先存在的x-forward -for报头时),'trust proxy'还有更多的选项可用。更多细节请参见链接指南。
  • 如果你的代理服务器没有填充x-forwarded-for头,有两种可能。
    1. 代理服务器不转发关于请求最初位置的信息。在这种情况下,将无法找到请求最初来自哪里。请先修改代理服务器的配置。
      • 例如,如果你使用nginx作为反向代理,你可能需要在你的配置中添加proxy_set_header X-Forwarded-For $remote_addr;
      • 李< / ul > < / >
      • 代理服务器以专有的方式(例如,自定义http报头)传递关于请求最初来自何处的信息。在这种情况下,这个答案是行不通的。可能有一种自定义的方式来获取该信息,但您需要首先了解其机制。
      • 李< / ol > < / >

nginx.conf文件中:
. txt proxy_set_header X-Real-IP $remote_addr; < / p >

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

注意,表示小写头

特别是对于node, http server组件的文档在活动连接下说:

当建立新的TCP流时触发。套接字是类型对象 net.Socket。通常用户不会想要访问这个事件。在 特别是,套接字将不会发出可读的事件,因为如何 协议解析器附加到套接字。插座也可以

. access at request.connection.

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

远端IP地址的字符串表示形式。例如, '74.125.127.100'或'2001:4860:a005::68'.

在express下,请求对象也是Node http请求对象的一个实例,因此这种方法仍然有效。

然而,在Express.js下,请求已经有两个属性:req.ipreq.ips

req.ip

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

req.ips

“信任代理”true时,解析“X-Forwarded-For”ip地址列表并返回一个数组,否则为空数组 返回。例如,如果值是“client, proxy1, proxy2” 将接收数组["client", "proxy1", "proxy2"],其中"proxy2"

值得一提的是,根据我的理解,Express req.ip是比req.connection.remoteAddress更好的方法,因为req.ip包含实际的客户端ip(前提是在Express中启用了可信代理),而另一个可能包含代理的ip地址(如果有的话)。

这就是为什么目前公认的答案是:

var IP = req。标题(“x-forwarded-for”)| | req.connection.remoteAddress; < /代码> < / p >

req.headers['x-forwarded-for']将等价于表达式req.ip

根据代理背后的表达,如果你正确配置了trust proxyreq.ip已经考虑了反向代理。因此,它比从网络层获得且不知道代理的req.connection.remoteAddress更好。

这对我来说比其他方法更有效。我的网站在CloudFlare后面,它似乎需要cf-connecting-ip

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

没有测试代理背后的表达,因为它没有说任何关于这个cf-connecting-ip头。

  1. 添加app.set('trust proxy', true)
  2. 按照通常的方式使用req.ipreq.ips

var ip = req.connection.remoteAddress;

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

headers对象有你需要的一切,只需要这样做:

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

我为此写了一个包。您可以将其用作表示中间件。我的包发布在这里: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);
});

我知道这个问题已经有了答案,但下面是我如何让我的问题起作用的。

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

这只是这个答案的附加信息。

如果你正在使用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之后,你将能够使用req.headers['x-real-ip'] || req.connection.remoteAddress;访问你的node/express应用程序路由中的ip

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

把所有的witk @kakopappa解决方案加上客户端ip地址的morgan日志:

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

在我的例子中,类似于解决方案,我最终使用以下x-forwarded-for方法:

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

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

如果你很好使用第三方库。你可以检查request-ip

你可以用is by

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 (Header可能返回多个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-ForwardedForwarded-ForForwarded(#2的变体)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

如果找不到IP地址,它将返回null

公开:我和图书馆没有关系。