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

Posted

技术标签:

【中文标题】如何在节点中确定用户的IP地址【英文标题】:How to determine a user's IP address in node 【发布时间】:2011-12-27 19:34:33 【问题描述】:

如何确定控制器内给定请求的 IP 地址?例如(快递):

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

【问题讨论】:

如果你使用 Express,你可以使用 req.ip source - expressjs.com/en/api.html#req.ip 试试这个:github.com/indutny/node-ip 对于那些在localhost 工作的人 - 就像我一样,下面所有答案的结果(几乎所有答案都有效)可能来自::1。这让我困惑了一段时间。后来发现::1是真实IP地址,是localhost的IPV6符号。 Hope this helps someone 【参考方案1】:

在您的request 对象中有一个名为socket 的属性,它是一个net.Socket 对象。 net.Socket 对象有一个属性remoteAddress,因此您应该能够通过此调用获取 IP:

request.socket.remoteAddress

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

编辑

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

【讨论】:

这给了我一个不同于 whatismyip.com 给我的 IP 地址。为什么会这样? 我的 API 服务安装在 no.de 实例上。当我尝试从我的计算机访问它时,我得到一个 IP 地址“10.2.XXX.YYY”,而我的真实世界 IP 是“67.250.AAA.BBB” 它是 request.headers['X-Forwarded-For'] 请注意,net.Stream 现在是 net.Socket,文档位于此处:nodejs.org/api/net.html#net_class_net_socket 对 Heroku 感兴趣的任何人:request.headers['x-forwarded-for']【参考方案2】:
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 在下面的 cmets 中针对未设置 x-forwarded-for 的情况提出了建议:

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

使用现代 JS 的建议:

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

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

【讨论】:

如何防止这些标头被欺骗? 这通常效果很好,但由于某种原因,我最近收到错误“无法读取未定义的属性'remoteAddress'”,因为显然所有内容都是空/未定义的,包括req.connection.socket。我不确定为什么/什么条件会导致这种情况,但最好检查 req.connection.socket 是否存在以避免发生这种情况时您的服务器崩溃。 最后一行 req.connection.socket.remoteAddress 抛出错误。小心点。 返回的ip地址为::1。为什么? 查看 pop() 的工作方式,您似乎将获得最后一个代理,而不是您想要的客户端。我错了吗?【参考方案3】:

如果使用快递...

req.ip

我正在查找这个然后我就像等待,我正在使用快递。呵呵。

【讨论】:

如果服务器在代理后面运行,将返回 127.0.0.1 的变体。使用Edmar's answer 或set x-real-ip。 @DanDascalescu 如果您设置了app.set('trust proxy', true)req.ip 将返回真实的 IP 地址,即使在代理之后也是如此。 Check the documentation for further information.【参考方案4】:

您可以保持 DRY,只使用支持 IPv4IPv6node-ipware。 p>

安装:

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 文件以了解高级选项。

【讨论】:

" 或者返回127.0.0.1表示无法确定用户的IP地址" 127.0.0.1和unknown有很大区别... 从 Heroku 测试时,它返回了一些奇怪的东西 :ffff:(not my IP address)。 @edmar-miyake 的回答对我来说很有效。 我想知道如果您在“x-forwarded-for”案例中使用 right2left 查找,IP 会是什么。 var ip_info = get_ip(req, right_most_proxy=True),在某些设置中,客户端 IP 可能是最正确的 IP。 该方法为我返回clientIp: '::1'。它似乎不起作用。 @JamEngulfer - ipware 仅在 IP 地址通过 request.headers[ ] 正确传递给您的应用程序时才有效。示例:AWS LBS 在“x-forwarded-for”中发送 IP 地址,而自定义 nginx 许多使用其他变量。 ipware 会尽最大努力找出 IP 地址,但前提是 IP 已在标头中传递。【参考方案5】:

您可以使用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();
;

希望对你有帮助

【讨论】:

在 github.com/pbojinov/request-ip/blob/master/index.js 检查包 request-ip 的源代码,它检查 x-forwarded-for 和各种其他流行负载均衡器(如 AWS ELB、Cloudflare、Akamai、nginx、Rackspace)的标头LB 和 Riverbed 的黄貂鱼 它为我返回null 同样的东西使用request.headers['x-forwarded-for']【参考方案6】:

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

【讨论】:

request.connection 已弃用,请改用套接字。【参考方案7】:

以下功能涵盖了所有案例将有所帮助

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

【讨论】:

请注意,我的 ips 之间有一个 , 在所有答案中,我认为这个是最好的。它是全面的,防御性编码为“三思而后行”。 request.connection 已弃用,请改用套接字【参考方案8】:

获取ip地址有两种方式:

    let ip = req.ip

    let ip = req.connection.remoteAddress;

但上述方法存在问题。

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

所以,获取用户IP地址的最佳解决方案是:-

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

【讨论】:

【参考方案9】:

警告:

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

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

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

【讨论】:

top answer 确实通过数组中的pop()ing 来处理这个问题,这比在索引 1 处获取元素更通用,可以通过curl --header "X-Forwarded-For: 1.2.3.4, 5.6.7.8" "https://example.com" 获取fooled。【参考方案10】:

function getCallerIP(request) 
    var ip = request.headers['x-forwarded-for'] ||
        request.connection.remoteAddress ||
        request.socket.remoteAddress ||
        request.connection.socket.remoteAddress;
    ip = ip.split(',')[0];
    ip = ip.split(':').slice(-1); //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
    return ip;

【讨论】:

你是对的,如果你想要ip作为字符串,那么你可以将最后一行替换为:ip = ip.split(':').slice(-1)[0]跨度> 不鼓励使用纯代码的答案。你能解释一下这个答案比旧的、更好的解释和(更多)赞成的answers 更好吗?【参考方案11】:

在节点 10.14 中,在 nginx 后面,您可以通过 nginx 标头请求它来检索 ip,如下所示:

proxy_set_header X-Real-IP $remote_addr;

然后在你的 app.js 中:

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

之后,无论您希望它出现在哪里:

var userIp = req.header('X-Real-IP') || req.connection.remoteAddress;

【讨论】:

【参考方案12】:

我都试过了,还是不行,

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 提供了一些其他信任代理值,您可以在他们的文档中查看这些值,但以下步骤对我有用。

    app.set('trust proxy', true) 在您的 Express 应用中。

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

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

【讨论】:

谢谢你!这最终是让我启动并运行的原因——对 nginx.conf 的修改(奇怪的是,没有其他人提到过)。【参考方案13】:

如果您使用的是 express 版本 3.x 或更高版本,您可以使用信任代理设置 (http://expressjs.com/api.html#trust.proxy.options.table),它将遍历 x-forwarded-for 标头中的地址链并将最新的 ip 放入将您未配置为可信代理的链放入 req 对象的 ip 属性中。

【讨论】:

【参考方案14】:

如果你有多个 IP,这对我有用:

var ipaddress = (req.headers['x-forwarded-for'] || 
req.connection.remoteAddress || 
req.socket.remoteAddress || 
req.connection.socket.remoteAddress).split(",")[0];

【讨论】:

【参考方案15】:

在nodejs中简单获取远程ip:

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

【讨论】:

【参考方案16】:

req.connection 已被弃用 since node@12.12.0。使用 req.connection.remoteAddress 获取客户端 IP 可能仍然有效,但不鼓励使用。

幸运的是,req.socket.remoteAddress 从 node@0.5.10 就一直存在,是一个完美的替代品:

远程 IP 地址的字符串表示形式。例如,'74.125.127.100''2001:4860:a005::68'。如果套接字被销毁(例如,如果客户端断开连接),则值可能是 undefined

【讨论】:

【参考方案17】:

如果您使用的是 express.js,那么,

app.post('/get/ip/address', function (req, res) 
      res.send(req.ip);
)

【讨论】:

【参考方案18】:

var ipaddress = (req.headers['x-forwarded-for'] || 
req.connection.remoteAddress || 
req.socket.remoteAddress || 
req.connection.socket.remoteAddress).split(",")[0];

【讨论】:

这个问题已经有了广为接受的答案。为什么这个代码示例比他们好?请添加更多解释。【参考方案19】:

我意识到这已经被回答到死了,但这是我编写的一个现代 ES6 版本,它遵循基于 airbnb 的 eslint 标准。

const getIpAddressFromRequest = (request) => 
  let ipAddr = request.connection.remoteAddress;

  if (request.headers && request.headers['x-forwarded-for']) 
    [ipAddr] = request.headers['x-forwarded-for'].split(',');
  

  return ipAddr;
;

X-Forwarded-For 标头可能包含以逗号分隔的代理 IP 列表。顺序是 client,proxy1,proxy2,...,proxyN。在现实世界中,人们实现了可以在此标头中提供他们想要的任何内容的代理。如果您在负载均衡器或其他设备后面,您至少可以相信列表中的第一个 IP 至少是某个请求通过的任何代理。

【讨论】:

【参考方案20】:

如果您使用的是 Graphql-Yoga,您可以使用以下功能:

const getRequestIpAddress = (request) => 
    const requestIpAddress = request.request.headers['X-Forwarded-For'] || request.request.connection.remoteAddress
    if (!requestIpAddress) return null

    const ipv4 = new RegExp("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.)3(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")

    const [ipAddress] = requestIpAddress.match(ipv4)

    return ipAddress

【讨论】:

【参考方案21】:

我在 nginx 后面使用 express 和

req.headers.origin

帮我搞定了

【讨论】:

【参考方案22】:

我将它用于 ipv4 格式

req.connection.remoteAddress.split(':').slice(-1)[0]

【讨论】:

【参考方案23】:
    const express = require('express')
    const app = express()
    const port = 3000

    app.get('/', (req, res) => 
    var ip = req.ip
    console.log(ip);
    res.send('Hello World!')
    )

   // Run as nodejs ip.js
    app.listen(port, () => 
    console.log(`Example app listening at http://localhost:$port`)
    )

【讨论】:

【参考方案24】:

这里有很多优点,但没有什么是全面的,所以这是我最终使用的:

function getIP(req) 
  // req.connection is deprecated
  const conRemoteAddress = req.connection?.remoteAddress
  // req.socket is said to replace req.connection
  const sockRemoteAddress = req.socket?.remoteAddress
  // some platforms use x-real-ip
  const xRealIP = req.headers['x-real-ip']
  // most proxies use x-forwarded-for
  const xForwardedForIP = (() => 
    const xForwardedFor = req.headers['x-forwarded-for']
    if (xForwardedFor) 
      // The x-forwarded-for header can contain a comma-separated list of
      // IP's. Further, some are comma separated with spaces, so whitespace is trimmed.
      const ips = xForwardedFor.split(',').map(ip => ip.trim())
      return ips[0]
    
  )()
  // prefer x-forwarded-for and fallback to the others
  return xForwardedForIP || xRealIP || sockRemoteAddress || conRemoteAddress

【讨论】:

【参考方案25】:

我们可以在 node js 中检查这段代码

const os       = require('os');
var interfaces = os.networkInterfaces();

var addresses = [];

for (var k in interfaces) 

    for (var k2 in interfaces[k]) 

        var address = interfaces[k][k2];

        if ( (address.family === 'IPv4' || address.family === 'IPv6')  && 
            !address.internal) 

            addresses.push(address.address);

        
    

console.log(addresses);

【讨论】:

一个好的答案将始终包括解释为什么这会解决问题,以便 OP 和任何未来的读者可以从中学习。【参考方案26】:

有同样的问题...我也是 javascript 新手,但我用 req.connection.remoteAddress 解决了这个问题;这给了我 IP 地址(但采用 ipv6 格式 ::ffff.192.168.0.101 ),然后 .slice 删除前 7 个数字。

var ip = req.connection.remoteAddress;

if (ip.length < 15) 
   
   ip = ip;

else

   var nyIP = ip.slice(7);
   ip = nyIP;

【讨论】:

这不是一个好方法,因为 ipv6 不仅仅是 7 位数字 + IPv4,而且可以完全不同。 @Radek 如果您验证地址的开头,它符合规范(请参阅en.wikipedia.org/wiki/IPv6_address ctrl-f 搜索“IPv4-mapped”)ip= (ip.length&lt;15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined)) 将替换 if... in以上代码 我亲自从 npm request-ip 包装 getClientIp() 以创建 function getClientIp4(req) var ip=typeof req==='string'?req:getClientIp(req); return (ip.length&lt;15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined)); ,它接受以前获取的 ip 或请求对象作为输入并给出 ip 或未定义的结果

以上是关于如何在节点中确定用户的IP地址的主要内容,如果未能解决你的问题,请参考以下文章

如何从vb6代码确定登录到Windows服务器的工作站的IP地址

如何在 Java 中确定我的路由器/网关的 IP?

在 Python 中,如何确定 IP 地址是不是是私有的?

如何在Excel中根据IP地址查找位置

如何使用 socket.io 获取用户的 IP 地址?

确定最终用户机器 MAC 地址和 IP 地址(本地和 ISP)