获取用户IP地址策略

获取用户真实IP的思路


推荐文章

阅读了不少相关的文章,列表如下,都写的不错


产生的问题以及解决方案

服务分层

每一种编程语言的Web开发框架都提供原生的方法可以获取连接到服务器的远程地址,这是网络四层结构中网络层的信息,代表远程socket连接的IP地址。

但是目前开发中于后端服务直接建立socket连接的往往都是负载均衡服务器或者是其它的服务,这就会导致获取的IP地址信息不准确。

解决方案是在接入层设置 X-Forwarded-For 请求头,或者在请求头中添加一个字段记录用户的IP地址。参考上面的第二篇文章中的内容,对于接入层的Nginx可以做如下配置

1
2
3
4
proxy_set_header            Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Nginx也一定会把直接请求Nginx的IP地址追加到X-Forwarded-For最右边
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

这样对于后台服务,可以尝试获得请求头中的 X-Real-IP 字段,或 X-Forwarded-For 字段对应的值的列表的第一个


用户的恶意

有些用户可能在发起请求时就在请求头中添加 X-Forwarded-For 字段,这样子就会破坏 X-Forwarded-For 字段对应的列表的正确性,比如或变成这样

1
curl -H 'X-Forwarded-For: 1.2.3.4' http://your.add
1
X-Forwarded-For: 1.2.3.4, client, proxy1, proxy2

这样的话服务端获取的 X-Forwarded-For 将不准确,不过这个问题可以通过获取 X-Real-IP 的方法解决。

但是上面的第三篇文章指出了一个问题:如果接入层不可控怎么办?它给出的解决方案是:

确定我们的部署架构上到底有多少个反向代理服务,从而在从 X-Forwarded-For 请求头中获取请求的真实 IP 时,过滤掉用户伪造的 IP 地址

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

上面的第四篇文章也对相关的问题做了详细的总结