客户端ip获取蹲坑启示: 不要侥幸

栏目: 数据库 · 发布时间: 5年前

内容简介:怎么获取一个客户端ip ? 我想这个问题,在网上遍地都是答案!而且多半是像下面这样:我也没说要去研究这玩意,我只是不想重复造轮子,然后努力找到了了代码仓库里有这么一段代码,所以,我就用来去获取ip了!

怎么获取一个客户端ip ? 我想这个问题,在网上遍地都是答案!

而且多半是像下面这样:

    
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

我也没说要去研究这玩意,我只是不想重复造轮子,然后努力找到了了代码仓库里有这么一段代码,所以,我就用来去获取ip了!

测试环境一切ok。然后稀拉拉地,上线了!

嘿,一上线之后,发现了数据库ip字段竟然有两个ip: 10.11.0.6, 202.116.0.83 。

好嘛,一看就知道是怎么回事了,这个用户的请求是通过代理进来的,而代理只是一种很正常的转发行为,所以必须处理这种情况!

由于原来我设置的ip字段大小为varchar(32), 所以装下这两个ip,是松的事! 大概查了下日志,并没有发现什么异常!

我想着吧,一般的用户也就是一级代理下,就差不多了。所以应该不会有什么问题,这个问题留给下个版本修复吧!

我就这么想着,玩去了。

然后,就被邮件报警了!数据库插入失败!

妈蛋,该来的始终要来!我还是太年轻了。

有一句叫: 如果你发现有个问题可能会发生,那么它就一定会发生!

不要侥幸,没人能跑得掉!

修复办法自然简单到没朋友,截取第一个',' 前的ip就行了!

    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        // 多级代理问题修复
        if (ip.indexOf(',') > 0) {
            ip = ip.substring(0, ip.indexOf(',')).trim();
        }

        return ip;
    }

好了,问题解决了,警告咱们要有敬畏之心。

下面,咱们来看看多级代理的ip是怎么回事?

在 nginx 中,咱们可以这么设置:

    location /api {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://10.11.20.22/api;
    }

这样的话,后续服务端就可以通过获取 X-Forwarded-For 来进行获取所有的代理ip地址链了!

格式为: X-Forwarded-For:10.11.247.1, 10.11.38.131, 10.11.255.1 ...

也就是说 X-Forwarded-For 是呈叠加的方式的,所以,我们应该只需要取到 第一个ip 就可以了!

事实上,X-Forwarded-For 是可以伪造的。

比如: curl -H "X-Forwarded-For:11.11.22.22" http://a.com/api

可以看到,确实很容易就进行伪造了。而按照后端代理服务器的设置,其只会往该header里添加自己的值,所以,如果此时咱们按照获取第一个值为ip,也就判断失误了。不过这种失误,一般我们还是可以接受的。不过有的场景就不适用了,比如我们通过ip来做权限管理时!所以,在做ip白名单时,还要考虑实际情况而行了!

好了,看得出通过代理标识获取ip是不可靠的,那么,有没有一种可靠的获取ip的方式呢?

其实是一个值是不可以改的:REMOTE_ADDR. 这个字段源于 tcp/udp 请求中,就会带有源地址,目标地址!

REMOTE_ADDR 是你的客户端跟你的服务器“握手”时候的IP。但是如果你使用了“匿名代理”,REMOTE_ADDR将显示代理服务器的IP。

所以,REMOTE_ADDR 虽然是不可改的,但是它却只能代表一级服务器ip,而面对现在复杂的网络环境,那是太无能为力了!

所以,没办法,还得通过约定的变量来,而这个变量又要依赖于使用的代理设置了。如上!虽然可以伪造,但是至少绝大部分是对的!

最后,给一个 tcp 发送数据样例( src -> dst):

客户端ip获取蹲坑启示: 不要侥幸


以上所述就是小编给大家介绍的《客户端ip获取蹲坑启示: 不要侥幸》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

领域驱动设计

领域驱动设计

[美] Eric Evans / 赵俐、盛海艳、刘霞 / 人民邮电出版社 / 2016-6-1 / 69

本书是领域驱动设计方面的经典之作,修订版更是对之前出版的中文版进行了全面的修订和完善。 全书围绕着设计和开发实践,结合若干真实的项目案例,向读者阐述如何在真实的软件开发中应用领域驱动设计。书中给出了领域驱动设计的系统化方法,并将人们普遍接受的一些实践综合到一起,融入了作者的见解和经验,展现了一些可扩展的设计新实践、已验证过的技术以及便于应对复杂领域的软件项目开发的基本原则。一起来看看 《领域驱动设计》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具