From d1ea1b142f21991fc3e64e5e9b92784e221ebb72 Mon Sep 17 00:00:00 2001 From: chaos-zhu Date: Sun, 26 Apr 2026 18:34:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=9B=B4=E6=AD=A3=E6=A0=87=E5=87=86?= =?UTF-8?q?=E5=8F=AF=E4=BF=A1=E4=BB=A3=E7=90=86IP=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/app/utils/tools.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/server/app/utils/tools.js b/server/app/utils/tools.js index 02f2ada..b137c8b 100644 --- a/server/app/utils/tools.js +++ b/server/app/utils/tools.js @@ -290,20 +290,32 @@ const isLoopbackIP = (ip) => { return firstOctet === 127 } +const isPrivateIPv4 = (ip) => { + if (!net.isIPv4(ip)) return false + const [first, second] = ip.split('.').map(Number) + return first === 10 || + (first === 172 && second >= 16 && second <= 31) || + (first === 192 && second === 168) +} + +const isTrustedProxyIP = (ip) => { + ip = normalizeIP(ip) + return isLoopbackIP(ip) || isPrivateIPv4(ip) || ip === 'fc00::' || ip === 'fd00::' +} + /** * 从连接中提取可信客户端 IP: * - 优先使用 TCP 层真实地址(socketRemoteAddress),不可被客户端伪造 - * - 仅当该地址为 loopback(即经过本机可信反向代理)时,才从 x-forwarded-for 取客户端 IP + * - 当该地址来自可信代理(本机或 Docker/内网反代)时,才从 x-forwarded-for 取客户端 IP * - nginx 使用 proxy_add_x_forwarded_for 时会将真实 IP 追加到末尾,故取最后一个值 - * 以防御客户端在头部预置伪造 IP 的攻击(XFF 首个值可伪造,末尾值由代理追加不可伪造) */ const getClientIP = (socketRemoteAddress, xForwardedFor) => { const socketIP = normalizeIP(socketRemoteAddress || '') - if (!isLoopbackIP(socketIP)) return socketIP + if (!isTrustedProxyIP(socketIP)) return socketIP if (!xForwardedFor) return socketIP - const parts = xForwardedFor.split(',') - const last = parts[parts.length - 1].trim() - return normalizeIP(last) || socketIP + + const parts = xForwardedFor.split(',').map(item => normalizeIP(item)).filter(Boolean) + return parts[parts.length - 1] || socketIP } const isAllowedIp = (requestIP) => {