如何在Node中确定用户的IP地址

518

我该如何在控制器中确定给定请求的IP地址?例如(在express中):

app.post('/get/ip/address', function (req, res) {
    // need access to IP address here
})

49
如果你正在使用Express,可以使用req.ip - FrickeFresh
尝试一下这个:https://github.com/indutny/node-ip - Stephen Last
62
对于那些像我一样从localhost工作的人,下面所有答案的结果几乎都会出现::1。这让我困惑了一段时间。后来发现::1是真正的IP地址,是本地主机的IPV6表示法。希望这能帮助到某些人。 - Pramesh Bajracharya
Cloudflare 获取客户端 IP req.headers['cf-connecting-ip'] - Muhammad Shahzad
33个回答

635

在你的 request 对象中有一个叫做 socket 的属性,它是一个 net.Socket 对象。 net.Socket 对象有一个属性叫做remoteAddress,因此您可以使用以下代码获取 IP 地址:

request.socket.remoteAddress

(如果您的Node版本低于13,请使用已弃用的现在request.connection.remoteAddress

编辑

如@juand在评论中指出,如果服务器在代理后面,则获取远程IP的正确方法是request.headers['x-forwarded-for']

编辑2

使用Node.js的express时:

如果设置了app.set('trust proxy', true),则req.ip将返回真实的IP地址,即使在代理后面。请查看文档以获取更多信息


15
这让我得到一个与whatismyip.com给出的IP地址不同的地址。这是为什么呢? - Shamoon
8
它是request.headers['X-Forwarded-For']。 - 0x6A75616E
5
请注意,net.Stream现在改为net.Socket,并且相关文档在此处:http://nodejs.org/api/net.html#net_class_net_socket - monsur
11
对于任何感兴趣的人,对于Heroku,它是:request.headers['x-forwarded-for'] - FueledPublishing
显示剩余13条评论

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

请注意,有时您可以在 req.headers['x-forwarded-for'] 中获得多个 IP 地址。此外,x-forwarded-for 标头并不总是存在,这可能会导致错误。

字段的一般格式为:

x-forwarded-for: client, proxy1, proxy2, proxy3

其中值是一个由逗号和空格分隔的 IP 地址列表,最左边的是原始客户端,每个后继代理传递请求时添加其接收请求的 IP 地址。在这个例子中,请求通过 proxy1proxy2,然后是 proxy3proxy3 出现为请求的远程地址。

这是由 Arnav Gupta 建议的解决方案,并且 Martin 在下面的评论中提出了修复方法,用于处理未设置 x-forwarded-for 的情况:

var ip = (req.headers['x-forwarded-for'] || '').split(',').pop().trim() || 
         req.socket.remoteAddress

使用现代JS的建议:

  • 仅在设置了x-forwarded-for时处理,如果设置了,则取第一个地址
  • 其他参数使用可选链操作符(?.)
const parseIp = (req) =>
    req.headers['x-forwarded-for']?.split(',').shift()
    || req.socket?.remoteAddress

console.log(parseIp(req))
// => 127.0.0.1

22
如何防止这些标头被欺骗? - Domi
8
通常情况下这个方法很有效,但最近我遇到了一个错误:“Cannot read property 'remoteAddress' of undefined”,因为似乎所有东西都是null/undefined,包括req.connection.socket。我不确定是什么原因或什么条件导致了这种情况,但最好检查一下req.connection.socket是否存在,以避免在发生此情况时使服务器崩溃。 - Matt Browne
9
最后一行代码req.connection.socket.remoteAddress报错了,请注意。 - yAnTar
25
返回的IP地址是::1。为什么? - Bagusflyer
6
@bagusflyer 这是你的本地 IP 地址。 - Andrei Shostik
显示剩余16条评论

146

如果使用express...

req.ip

我在查询这个内容时,突然意识到自己正在使用express。傻瓜。


2
如果服务器在代理后运行,则返回127.0.0.1的变体。请使用Edmar的答案设置x-real-ip - Dan Dascalescu
9
如果你设置了app.set('trust proxy', true),即使在代理后面,req.ip也会返回真实的IP地址。 查看文档获取更多信息 - Ahmed Tounsi

35

您可以保持代码的干燥性并使用支持IPv4IPv6node-ipware

安装:

npm install ipware

在你的 app.js 或中间件中:

var getIP = require('ipware')().get_ip;
app.use(function(req, res, next) {
    var ipInfo = getIP(req);
    console.log(ipInfo);
    // { clientIp: '127.0.0.1', clientIpRoutable: false }
    next();
});
它将尽最大努力获取用户的IP地址,或返回 127.0.0.1 来表示无法确定用户的IP地址。查看README文件以了解高级选项。

45
" 或返回127.0.0.1以指示无法确定用户的IP地址" 127.0.0.1和未知之间有很大的区别... - Nepoxx
7
当我从Heroku进行测试时,它返回了一些稀奇古怪的东西:ffff:(不是我的IP地址)。@edmar-miyake的答案对我有效。 - Nilloc
如果在“x-forwarded-for”情况下使用从右到左的查找,IP会是什么呢?例如,在某些设置中,客户端IP可能是最右边的IP。因此,可以使用“get_ip(req,right_most_proxy = True)”来获取IP信息。 - Avid Coder
4
这个方法对我返回了 clientIp: '::1'。看起来它不起作用。 - JamEngulfer
1
@GervasiusTwinklewinkleson 客户的请求只提供了一个IP地址给服务器,因此它可能是IPv4、IPv6或IPv4封装在IPv6中。 - undefined
显示剩余4条评论

27
您可以使用request-ip来获取用户的IP地址。它可以处理许多不同的边缘情况,其中一些在其他答案中提到。
披露:我创建了这个模块 安装:
npm install request-ip

在你的应用中:

var requestIp = require('request-ip');

// inside middleware handler
var ipMiddleware = function(req, res, next) {
    var clientIp = requestIp.getClientIp(req); // on localhost > 127.0.0.1
    next();
};

希望这能有所帮助。


4
检查 https://github.com/pbojinov/request-ip/blob/master/index.js 包 request-ip 的源代码,它会检查 x-forwarded-for 和其他流行负载均衡器的各种头文件,如 AWS ELB、Cloudflare、Akamai、nginx、Rackspace LB 和 Riverbed's Stingray。 - Giorgio
1
对我来说它返回null. - S.M_Emamian
使用request.headers['x-forwarded-for']代替相同的事情 - Prathamesh More
如果客户同时拥有IPv4和IPv6,我猜应该没有办法同时获取两者吧? - undefined
request.headers['x-forwarded-for'] 是许多可能包含用户IP的标头之一。这就是为什么我着手创建了 request-ip 包。 - undefined

18

request.headers['x-forwarded-for'] || request.connection.remoteAddress

如果存在x-forwarded-for头,则使用该头信息,否则使用.remoteAddress属性。 x-forwarded-for头在传递通过负载均衡器(或其他类型的代理)为HTTPHTTPS设置的请求时添加(也可以在使用代理协议进行TCP级别负载平衡时将该头添加到请求中)。这是因为request.connection.remoteAddress属性将包含负载平衡器的私有IP地址而不是客户端的公共IP地址。通过使用上述顺序的OR语句,您可以检查是否存在x-forwarded-for头并在存在时使用它,否则使用request.connection.remoteAddress


请求连接已过时,请使用套接字。 - GorvGoyl

18

我试过所有的方法,但都没有成功。

console.log(clientIp);
console.log(req.ip);

console.log(req.headers['x-forwarded-for']);
console.log(req.connection.remoteAddress);
console.log(req.socket.remoteAddress);
console.log(req.connection.socket.remoteAddress.split(",")[0]);

在使用Nginx代理Express应用程序时,需要将应用程序变量trust proxy设置为true。Express提供了一些其他的trust proxy值,您可以在其文档中查看,但是以下步骤适用于我。

  1. 在Express应用程序中添加app.set('trust proxy', true)

app.set('trust proxy', true);

  1. 在Nginx配置文件的服务器块中添加proxy_set_header X-Forwarded-For $remote_addr
  location /  {
                proxy_pass    http://localhost:3001;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $remote_addr;  # this line
                proxy_cache_bypass $http_upgrade; 
        }
现在您可以从req.header('x-forwarded-for')或req.connection.remoteAddress读取客户端的IP地址;ipfilter的完整代码。
module.exports =  function(req, res, next) {
    let enable = true; // true/false
    let blacklist = ['x.x.x.x'];
    let whitelist = ['x.x.x.x'];
    let clientIp = req.header('x-forwarded-for') || req.connection.remoteAddress;
    if (!clientIp) {
        return res.json('Error');
    }
    if (enable
        && paths.some((path) => (path === req.originalUrl))) {

        let blacklist = blacklist || [];
        if (blacklist.some((ip) => clientIp.match(ip) !== null)) {
            return res.json({ status: 401, error: 'Your IP is black-listed !'});
        }
        let whitelist = whitelist || [];
        if (whitelist.length === 0 || whitelist.some((ip) => clientIp.match(ip) !== null)) {
            next();
            return;
        } else {
            return res.json({ status: 401, error: 'Your IP is not listed !'});
        }
    }
    next();
};

3
谢谢您!这最终让我成功运行了——修改nginx.conf文件(奇怪的是,没有其他人提到过)。 - Netside

17

以下函数涵盖了所有情况,将会有所帮助

var ip;
if (req.headers['x-forwarded-for']) {
    ip = req.headers['x-forwarded-for'].split(",")[0];
} else if (req.connection && req.connection.remoteAddress) {
    ip = req.connection.remoteAddress;
} else {
    ip = req.ip;
}console.log("client IP is *********************" + ip);

请注意,IP地址之间需要用逗号和空格分隔。 - ThomasReggi
在所有的答案中,我认为这个是最好的。它很全面,并且采用了“三思而后行”的防御性编码。 - KANJICODER
request.connection已被弃用,请使用socket代替。 - GorvGoyl

14

警告:

不要盲目地将此用于重要的速率限制:

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

这很容易被欺骗:

curl --header "X-Forwarded-For: 1.2.3.4" "https://example.com"

在这种情况下,用户的真实IP地址将是:

let ip = request.headers['x-forwarded-for'].split(',')[1];

我很惊讶其他答案都没有提到这一点。


4
这个 最佳答案 通过 pop() 方法处理这个问题,比获取索引1处的元素更普适,因为索引1处的元素可能会被 伪造,使用 curl --header "X-Forwarded-For: 1.2.3.4, 5.6.7.8" "https://example.com" 即可。 - Dan Dascalescu

10

获取IP地址有两种方式:

  1. let ip = req.ip

  2. let ip = req.connection.remoteAddress;

但是以上方法存在一个问题。

如果您的应用程序在Nginx或任何代理后面运行,则每个IP地址都将是127.0.0.1

因此,获得用户IP地址的最佳解决方案是:

let ip = req.header('x-forwarded-for') || req.connection.remoteAddress;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接