如何在节点中确定用户的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 地址。在此示例中,请求通过proxy1
、proxy2
,然后是proxy3
。 proxy3
显示为请求的远程地址。
这是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,只使用支持 IPv4 和 IPv6 的 node-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
标头添加到通过为 HTTP 或 HTTPS 设置的负载平衡器(或其他类型的代理)的请求(也可以添加当使用 代理协议 在 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<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<15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined));
,它接受以前获取的 ip 或请求对象作为输入并给出 ip 或未定义的结果以上是关于如何在节点中确定用户的IP地址的主要内容,如果未能解决你的问题,请参考以下文章