Node.js获取remoteAddress返回服务器地址而非客户端IP如何解决
问题背景
使用Node.js(v16.15.1)搭配Express框架开发时,执行以下代码尝试获取客户端远程地址:
console.log(req.connection.remoteAddress) console.log(req.socket.remoteAddress)
两个属性返回结果完全一致,均为::ffff:123.123.123.123格式的地址,但该地址实际为服务器自身地址,并非客户端真实访问IP,无法满足获取客户端IP的业务需求。当前部署环境未使用代理,仅配置了常规的443端口到服务监听端口5000的端口转发规则。
问题根因
req.connection.remoteAddress和req.socket.remoteAddress获取的是与Node.js进程建立TCP连接的直接对端IP,出现返回服务器自身地址的原因是端口转发环节对报文源IP做了源地址转换(SNAT),导致Node进程收到的请求源IP被改写为服务器本机地址。常见触发场景包括:
- 配置iptables/firewalld端口转发时,错误添加了MASQUERADE/SNAT规则,将转发到5000端口的流量源IP统一替换为服务器本地地址
- Express服务仅监听127.0.0.1回环地址,443端口的流量经内核转发到回环地址时触发源地址改写
- 云平台端口转发规则默认未开启源IP保留,平台侧将转发流量的源IP替换为服务器内网地址
修复方案
- 清理端口转发的多余SNAT规则
若使用iptables配置转发,执行以下命令查看nat表规则,删除针对5000端口的MASQUERADE/SNAT规则:
若使用firewalld配置转发,移除针对本地5000端口的端口转发伪装配置:# 查看nat表POSTROUTING链规则 iptables -t nat -nL POSTROUTING # 找到对应规则后,将-A替换为-D执行删除,示例如下 iptables -t nat -D POSTROUTING -p tcp --dport 5000 -j MASQUERADEfirewall-cmd --remove-masquerade --permanent firewall-cmd --reload - 调整Express服务监听配置
不要让服务仅绑定回环地址,改为监听所有网卡地址,避免流量经过回环转发被改写源IP:// 正确监听示例,绑定0.0.0.0允许所有IPv4地址访问 app.listen(5000, '0.0.0.0', () => { console.log('服务已启动在5000端口') }) - 优先使用Express封装的API获取IP
不需要手动读取底层socket属性,直接使用框架提供的req.ip获取客户端地址即可,::ffff:是IPv4映射IPv6的正常前缀,需要纯IPv4格式时直接截取该前缀即可:const clientIp = req.ip.replace('::ffff:', '') - 云平台转发规则检查
若使用云服务商提供的端口转发/负载均衡功能,在对应控制台找到端口转发配置项,手动开启「保留客户端源IP」开关即可。
注:
::ffff:123.123.123.123是IPv6双栈环境下的IPv4地址表示格式,不属于异常格式,仅需确认IP值是否为真实客户端IP即可。
内容的提问来源于stack exchange,提问作者Okilele
相关产品推荐
相关产品推荐

