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

Sha*_*oon 318 api ip node.js

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

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

top*_*pek 418

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

request.connection.remoteAddress
Run Code Online (Sandbox Code Playgroud)

请参阅httpnet的文档

编辑

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

  • 它是request.headers ['X-Forwarded-For'] (7认同)
  • 返回"NULL" (5认同)
  • 这给了我一个不同于whatismyip.com给我的IP地址.那为什么会这样? (4认同)
  • 请注意,net.Stream现在是net.Socket,文档位于此处:http://nodejs.org/api/net.html#net_class_net_socket (4认同)
  • 我在http://no.de实例上安装了我的API服务.当我尝试从我的计算机访问它时,我得到一个"10.2.XXX.YYY"的IP地址,而我的真实世界IP是"67.250.AAA.BBB" (3认同)
  • 对于任何有兴趣的人,对于Heroku来说:`request.headers ['x-forwarded-for']` (3认同)
  • 是否可以欺骗`request.connection.remoteAddress`,或者这可以安全地用作接受IP连接的防护吗? (2认同)
  • 该答案现已弃用 /sf/answers/4615025201/ (2认同)

Edm*_*ake 379

var ip = req.headers['x-forwarded-for'] || 
     req.connection.remoteAddress || 
     req.socket.remoteAddress ||
     (req.connection.socket ? req.connection.socket.remoteAddress : null);
Run Code Online (Sandbox Code Playgroud)

请注意,有时您可以获得多个IP地址req.headers['x-forwarded-for'].此外,x-forwarded-for不会始终设置标头,这可能会引发错误.

该领域的一般格式是:

的x转发换: client, proxy1, proxy2, proxy3

其中值是逗号+空格分隔的IP地址列表,最左边是原始客户端,每个连续的代理通过请求添加接收请求的IP地址.在此示例中,请求通过proxy1,proxy2然后传递proxy3.proxy3显示为请求的远程地址.

这是Arnav Gupta建议的解决方案,马丁在下面的评论中为x-forwarded-for未设置的案例提出了修正:

var ip = (req.headers['x-forwarded-for'] || '').split(',').pop() || 
         req.connection.remoteAddress || 
         req.socket.remoteAddress || 
         req.connection.socket.remoteAddress
Run Code Online (Sandbox Code Playgroud)

  • 最后一行req.connection.socket.remoteAddress抛出错误.小心点. (9认同)
  • 返回的ip地址是:: 1.为什么? (9认同)
  • 这通常很好但但由于某种原因我最近得到错误"无法读取属性'remoteAddress'的undefined"因为显然一切都是null/undefined,包括`req.connection.socket`.我不确定为什么/什么条件会导致这种情况但最好检查`req.connection.socket`是否存在以避免服务器在发生这种情况时崩溃. (8认同)
  • 如何防止这些标题的欺骗? (7认同)
  • @ZhouHao它是你的IPv6格式的ip地址 (6认同)
  • 这是不对的,这会为您提供到达服务器之前的最后一个代理,而不是客户端的 IP,这是数组中的第一个 IP。`req.headers['x-forwarded-for'] || '').split(',')[0]` 是客户端的IP (4认同)
  • 如果您在设置这些标头的代理后面,它将添加到地址列表的末尾。最后一个将由您的代理设置,前一个可能来自以前的负载均衡器或来自客户端的“欺骗”。我想您也可以告诉LB覆盖标头。 (2认同)
  • ^ 你会想了解什么是核心节点 web 服务器相关的模块,以及什么是 express http://expressjs.com (2认同)
  • 请注意:regexp仅适用于IPv4,不应在生产中使用。 (2认同)
  • @bagusflyer这是您的localhost IP地址 (2认同)
  • 查看pop()的工作方式,似乎您将要获得最后一个代理,而不是您想要的客户端。我错了吗? (2认同)
  • 我同意@Michel 我会使用 `shift()` (2认同)
  • 问题:当`x-forwarded-for`返回`undefined`时发生错误.修复:添加`|| 在阅读标题后"`` 最后:`var ip =(req.headers ['x-forwarded-for'] ||'').split(',').pop()...` (2认同)
  • 没有人惊讶地提到这一点。您需要修剪数组结果,以防x-forwarded-for返回多个ip。否则,您将获得一个无效的IP地址,并带有前导空格。像`req.headers ['x-forwarded-for'] ||一样 '').split(',')。pop()。trim();`或用逗号和空格`split(,)`进行拆分 (2认同)
  • @Bagusflyer ```::1``` 是 IPv6 中的环回地址。它就像 IPv6 版本的 127.0.0.1。 (2认同)

Jas*_*ing 69

如果使用快递...

req.ip

我正在看这个,然后我就像等待,我正在使用快递.咄.

  • @DanDascalescu 如果您设置 `app.set('trust proxy', true)`,则 `req.ip` 将返回真实的 IP 地址,即使在代理之后也是如此。[查看文档以获取更多信息](http://expressjs.com/en/4x/api.html#req.ip)。 (9认同)
  • 如果服务器在代理后面运行,将返回 127.0.0.1 的变体。使用[Edmar的答案](/sf/ask/567549951/#19524949)或[set x-real-ip]( /sf/ask/567549951/#53819302)。 (2认同)

un3*_*33k 29

您可以保持DRY并且只使用支持IPv4IPv6的node-ipware.

安装:

npm install ipware
Run Code Online (Sandbox Code Playgroud)

在您的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();
});
Run Code Online (Sandbox Code Playgroud)

它将尽最大努力获取用户的IP地址或返回127.0.0.1以指示它无法确定用户的IP地址.查看README文件以获取高级选项.

  • "或返回127.0.0.1表示无法确定用户的IP地址"127.0.0.1和未知之间存在很大差异...... (38认同)
  • 当从Heroku测试时,它为我返回了一些奇怪的东西`:ffff :(不是我的IP地址)` @ edmar-miyake的回答对我来说很合适. (4认同)
  • 那个方法为我返回`clientIp:':: 1'`.它似乎不起作用. (2认同)

pbo*_*nov 18

您可以使用request-ip来检索用户的IP地址.它处理了相当多的不同边缘情况,其中一些在其他答案中提到.

披露:我创建了这个模块

安装:

npm install request-ip
Run Code Online (Sandbox Code Playgroud)

在您的应用中:

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();
};
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助

  • 在 https://github.com/pbojinov/request-ip/blob/master/index.js 检查包 request-ip 的源代码,它会检查 x-forwarded-for 和各种其他流行负载均衡器的标头,例如AWS ELB、Cloudflare、Akamai、nginx、Rackspace LB 和 Riverbed 的 Stingray (3认同)

Ben*_*ies 17

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

如果x-forwarded-for标题在那里然后使用它,否则使用该.remoteAddress属性.

The x-forwarded-for header is added to requests that pass through load balancers (or other types of proxy) set up for HTTP or HTTPS (it's also possible to add this header to requests when balancing at a TCP level using proxy protocol). This is because the request.connection.remoteAddress property will contain the private ip address of the load balancer rather than the public ip address of the client. By using an OR statement, in the order above, you check for the existence of an x-forwarded-for header and use it if it exists otherwise use the request.connection.remoteAddress.


ash*_*e11 12

以下函数已涵盖所有案例将有所帮助

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);
Run Code Online (Sandbox Code Playgroud)


Ahm*_*yah 7

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;
}
Run Code Online (Sandbox Code Playgroud)


小智 7

获取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;
Run Code Online (Sandbox Code Playgroud)


小智 7

在节点 10.14 中,在 nginx 后面,您可以通过像这样通过 nginx 标头请求来检索 ip:

proxy_set_header X-Real-IP $remote_addr;
Run Code Online (Sandbox Code Playgroud)

然后在你的 app.js 中:

app.set('trust proxy', true);
Run Code Online (Sandbox Code Playgroud)

之后,无论您希望它出现在何处:

var userIp = req.header('X-Real-IP') || req.connection.remoteAddress;
Run Code Online (Sandbox Code Playgroud)


小智 7

Warning:

Don't just blindly use this for important rate-limiting:

let ip = request.headers['x-forwarded-for'].split(',')[0];
Run Code Online (Sandbox Code Playgroud)

It's very easy to spoof:

curl --header "X-Forwarded-For: 1.2.3.4" "https://example.com"
Run Code Online (Sandbox Code Playgroud)

In that case ther user's real IP address will be:

let ip = request.headers['x-forwarded-for'].split(',')[1];
Run Code Online (Sandbox Code Playgroud)

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

  • [最佳答案](/sf/ask/567549951/#19524949)确实通过“pop()”处理这个问题从数组中获取,这比获取索引 1 处的元素更通用,可以通过 `curl --header "X-Forwarded-For 来欺骗](/sf/answers/3660023111/): 1.2.3.4、5.6.7.8““https://example.com”`。 (4认同)

Mic*_*ang 6

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


kin*_*neo 5

我已经尝试了所有这些都不起作用,

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]);
Run Code Online (Sandbox Code Playgroud)

在 Nginx 代理后面运行 Express 应用程序时,您必须将应用程序变量 trust proxy 设置为 true。Express 提供了一些其他信任代理值,您可以在他们的文档中查看这些值,但以下步骤对我有用。

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

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; 
        }
Run Code Online (Sandbox Code Playgroud)
  1. 您现在可以从 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();
};
Run Code Online (Sandbox Code Playgroud)

  • 这次真是万分感谢!这最终是我启动并运行的原因——对 nginx.conf 的修改(奇怪的是,没有其他人提到)。 (3认同)

小智 5

如果你使用的是express.js,

app.post('/get/ip/address', function (req, res) {
      res.send(req.ip);
})
Run Code Online (Sandbox Code Playgroud)


小智 5

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

  • 对于这个问题,已经有一些广受好评的答案。为什么这个代码示例比他们更好?请添加更多解释。 (3认同)