Koa框架获取用户真实IP

简介

我们的 Web 服务,往往需要获取用户的真实 IP,譬如防刷、API限流等等场景。

每一个 TCP 连接都有 remoteAddress 属性,通过它可以直接获取到请求的 IP 地址。
而在 HTTP 请求中,我们可以通过 request.socket.remoteAddress 访问到这个属性

一般来说我们的应用服务都不会直接接收外部的请求,而会将服务部署在接入层之后,从而实现多台机器的负载均衡和服务的平滑发布,保证高可用。如阿里云 SLBNginx 反向代理。
此时,我们通过 remoteAddress 获取到的就是代理服务器的 IP 而不是用户的真实 IP

这是时候可以通过 X-Forwarded-For 请求头获取
所有的反向代理都实现一个统一的约定,在转发请求给下游服务之前,把请求代理的 IP 地址写入到 X-Forwarded-For 头中,形成了一个 IP 地址列X-Forwarded-For: client, proxy1, proxy2

实现

  • utils/目录下新建ip.js文件
function getClientIP(req) { let ip= req.headers['x-forwarded-for'] || // 判断是否有反向代理 IP req.ip || req.connection.remoteAddress || // 判断 connection 的远程 IP req.socket.remoteAddress || // 判断后端的 socket 的 IP req.connection.socket.remoteAddress || '' if(ip) { ip = ip.replace('::ffff:', '') } return ip; } module.exports = { getClientIP }
  • 代码中使用
const { getClientIP } = require('../utils/ip') router.get('/test', async ctx => { const ip = getClientIP(ctx) ctx.success({ ip }) })

问题

用户如果在请求中直接加入 X-Forwarded-For 的请求头,就可以伪装请求的 IP
这种情况需要确定我们的部署架构上到底有多少个反向代理服务,从而在从 X-Forwarded-For 请求头中获取请求的真实 IP 时,过滤掉用户伪造的 IP 地址

// 伪代码 // [ illegalIp, clientRealIp, proxyIp1, proxyIp2 ...] const val = ctx.get('X-Forwarded-For'); let ips = val ? val.split(/\s*,\s*/) : []; ips = ips.slice(-(maxProxyCount + 1));

Egg.js 直接内置提供了对应的解决方案

  • 修改config/config.default.js
config.proxy = true; // 这里配置的就是经过了多少个反向代理服务 config.maxProxyCount = 1;
  • 在代码中获取信息
ctx.ip // 获取用户的 IP 地址 ctx.host // 获取用户请求的域名 ctx.protocol // 获取用户请求的协议

创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: