资讯专栏INFORMATION COLUMN

从如何获取可信赖的ip地址聊起

wua_wua2012 / 2538人阅读

摘要:这是一个被爆出来的随机数漏洞,如果我知道了服务端的随机数漏洞,那么完全可以利用这一点来伪造出一个完美的假。

原文:http://www.l4zy.com/posts/how-to-get-real-ip-address.html

起因

写这篇文章缘起SF的一个问题 http://segmentfault.com/q/1010000000686700/a-1020000000687155。由此我想到了很多,就和大家随便聊聊吧

在PHP中获取ip地址有一段网上流传甚广的代码,还有它的各种变种

function real_ip()
{
    static $realip = NULL;

    if ($realip !== NULL)
    {
        return $realip;
    }

    if (isset($_SERVER))
    {
        if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]))
        {
            $arr = explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"]);

            /* 取X-Forwarded-For中第一个非unknown的有效IP字符串 */
            foreach ($arr AS $ip)
            {
                $ip = trim($ip);

                if ($ip != "unknown")
                {
                    $realip = $ip;

                    break;
                }
            }
        }
        elseif (isset($_SERVER["HTTP_CLIENT_IP"]))
        {
            $realip = $_SERVER["HTTP_CLIENT_IP"];
        }
        else
        {
            if (isset($_SERVER["REMOTE_ADDR"]))
            {
                $realip = $_SERVER["REMOTE_ADDR"];
            }
            else
            {
                $realip = "0.0.0.0";
            }
        }
    }
    else
    {
        if (getenv("HTTP_X_FORWARDED_FOR"))
        {
            $realip = getenv("HTTP_X_FORWARDED_FOR");
        }
        elseif (getenv("HTTP_CLIENT_IP"))
        {
            $realip = getenv("HTTP_CLIENT_IP");
        }
        else
        {
            $realip = getenv("REMOTE_ADDR");
        }
    }

    preg_match("/[d.]{7,15}/", $realip, $onlineip);
    $realip = !empty($onlineip[0]) ? $onlineip[0] : "0.0.0.0";

    return $realip;
}

这段代码的原理是从HTTP_X_FORWARDED_FOR以及HTTP_CLIENT_IP还有REMOTE_ADDR中获取ip地址。

这段代码有问题吗?如果从功能角度来看,它是没有问题的,因为它保证了你可以尽可能地获取到一个ip地址,如果你地程序不需要验证这个ip地址是否正确,只是为了显示它的来源,那么你可以这样做没问题。

但是很多情况下我们需要确切地知道当前跟服务器连接的是哪个ip,那这段代码就不妥了。

在PHP的$_SERVER变量中,凡是以HTTP_开头的键值都是直接从客户端的HTTP请求头中直接解析出来的。

这句话啥意思,意思就是客户端告诉你ip是多少就是多少,伪造它的成本可以说非常低。除了这两个以HTTP_开头的地址外,还有一个REMOTE_ADDR地址,这个地址是与你的服务器进行实际tcp连接的地址,它是一个可信赖的地址。要伪造这个地址成本很高,这是由于TCP三次握手协议的原理决定的,除非你能骗过服务器端的路由,那这样的成本就太高了,还不如直接黑进你的服务器

衍生

上图是一个经过简化的TCP握手协议,握手就是指在你正式传输信息之前,客户端和服务端确认双方是否可信的过程,这三步可以通俗化成下面的过程

小C (Client) 向小S (Server) 发了一封信(SYN),告诉它我要寄一个包裹 (数据) 给你,但是为了保证这个包裹你能收到,我先发一封信确认下你的地址 (Server IP) 是不是正确的,怎么确认呢?收到这封信后请按信上的地址 (Client IP) 回信就行了。

小S收到了这封信以后一想,我不仅要回信确认我的地址是存在的(ACK),还要问问你的地址是不是正确的,要不然我咋知道你是不是靠谱的人。于是小S给小C发了一封回信,不仅在信里确认自己的地址是正确的(ACK),也要求(SYN)小C在收到信件后给自己发一封回信,以确认他的地址也是真实的。要不然我会拒绝你的连接

小C在收到小S的确认后,马上发了一封回信(ACK)告诉我已经收到信了

从此它们就可以愉快的通信了。

那么问题来了

如果小C没有收到小S的确认信,但他也发了一封回信骗小S说自己已经收到了,怎么破?

这个问题实际上在TCP协议中已经解决了,每个SYN请求都会包含一个随机数字,发送回信ACK的时候,必须一并将这个数字加一再发回去。这样我们收到ACK的时候只要确认这个值是否正确就行了。

如果邮政局被收买了怎么?

这确实是一个风险,这就是我刚才提到的,路由器被黑掉的可能。这也就是很多人为什么说互联网的基础是非常脆弱的,只要公网上的其中一个路由器说了假话,所有经过这个路由器的数据都会变成不可信的。

但同时这个成本非常高,因为路由器的安全级别通常是很高的,而且一般的路由器管理端口也不会向普通访问者开放。所以能做到这一点的黑客,通常会选择直接去黑你的服务器。

这就好比我为了寄点东西噁心你一下,还要去贿赂一整个邮政局,显然不划算。还不如我直接买张火车票,赶到你的住处,把你门撬了,放你桌上。

再发散下

SYN FLOOD攻击

也就是SYN洪水攻击,看了上面的解释你应该大概知道SYN是啥意思了,就是一个询问包。所谓SYN洪水攻击就是指Client发送第一个SYN包的时候,告诉Server的源地址是一个假的,当Server发送回执时会进入到一个half-open(半开)状态。

为啥叫半开,因为这个端口只开了一半,握手过程已经开始,但还有一半没完成。这个半开连接大家应该都听过,早先玩迅雷下载或者bt的时候都需要打一个windows半开连接数补丁,就是因为桌面操作系统的计算资源是优先倾向于GUI的,当系统处于半开连接时因为处于等待状态,是会消耗内存和计算资源的,所以操作系统会默认把这个值调低,限制你能接受的连接。而我们p2p下载又需要比较高的连接量,所以就有了这个补丁,把它的限制打开。

我花这段篇幅解释半开连接数并不是没事找事,这其实就是SYN FLOOD攻击的原理。因为当系统处于半开状态时要消耗资源,而服务器往往半开连接数限制都比较大(或者干脆没限制),因此接第一段的话,因为服务器得到的源地址是个假的,发送回执后肯定会收不到确认,因此就会进入到漫长的等待过程(相对于响应时间)。攻击者通过伪造大量的这种无效请求,使服务器端等待大量连接,从而耗尽服务器资源,以达到使其瘫痪的目的。

想看看你是不是受到了此种攻击,只需要在netstat时看看是不是有大量的SYN_RCVD连接即可。SYN_RCVD表示服务器处于握手的第二步。

随机数的漏洞

我先将刚刚讲过的一个问题引用下

  

如果小C没有收到小S的确认信,但他也发了一封回信骗小S说自己已经收到了,怎么破?
这个问题实际上在TCP协议中已经解决了,每个SYN请求都会包含一个随机数字,发送回信ACK的时候,必须一并将这个数字加一再发回去。

这段话段的关键在于“随机数”这三个字,因为我们这个验证过程的一大基础是Server生成的随机数是不可能被Client端提前知道的,这就好比打扑克时你不可能知道其他人的牌是什么,一个道理。

但如果这个Client是个赌神呢?

  

http://www.securityfocus.com/bid/25348/discuss
根据安全机构的研究,Linux内核中包含了一个可导致Dos和权限提升的漏洞,可以被黑客利用来运行攻击代码。这是一个核心内存的堆栈溢出问题,可以导致系统的崩溃,再特定的环境下,还可以提升权限。这个漏洞影响到了Linux内核2.6.22.3前的版本。

这是一个被爆出来的随机数漏洞,如果我知道了服务端的随机数漏洞,那么完全可以利用这一点来伪造出一个完美的假ip。

最后弱弱地总结下

那我们到底该相信哪个ip呢?

首选REMOTE_ADDR,因为虽然有如此多地伪造方法,但在语言层面你只能选一个最可靠地。

如果你地服务隐藏在负载均衡或者缓存系统后面,它通常会给你发一个Client-Ip或者X-Forwarded-For的HTTP头,告诉你跟它连接的客户端ip,这时的HTTP_CLIENT_IPHTTP_X_FORWARDED_FOR是可信的,因为它是从前端服务器上的直接传递过来的,当然你必须在程序中指定只信任这一个来源,而不要像最开始的代码那样每个都检测一遍

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/11122.html

相关文章

  • 如何获取可信赖的ip地址聊起

    摘要:这是一个被爆出来的随机数漏洞,如果我知道了服务端的随机数漏洞,那么完全可以利用这一点来伪造出一个完美的假。 原文:http://www.l4zy.com/posts/how-to-get-real-ip-address.html 起因 写这篇文章缘起SF的一个问题 http://segmentfault.com/q/1010000000686700/a-10200000006871...

    W4n9Hu1 评论0 收藏0
  • 网络协议及编码

    摘要:协议族协议协议协议应用程序通过套接字对协议和协议所提供的服务进行访问。网络层完成将分组报文传输到它的目的地,即路由功能,一般采用协议。程序间达成的这种包含了信息交换的形式和意义的共识称为协议。 TCP/IP协议族:IP协议、TCP协议、UDP协议 showImg(https://segmentfault.com/img/bVvwxE); 应用程序通过套接字API对UPD协议和TCP协议...

    fizz 评论0 收藏0
  • ssh免密登录服务器和scp的使用

    摘要:原理远程主机收到用户的登录请求,把自己的公钥发给用户。也就是说,要实现免密码登入,首先要设置钥匙。把公钥放到远程服务器比如我的基本都安装了,万一没有,上。TL;DR 本地登录服务器 ssh user@remote -p port,端口是22的话ssh user@remote,退出登录exit 本地免密码登录 ssh-copy-id user@remote -p port,这在写脚本服务器控...

    Jochen 评论0 收藏0
  • 云计算漏洞风险的识别与应对措施

    摘要:相比之下,在年月进行的一次调查中的中小型受访企业表示,他们所使用的基于云计算的应用程序的安全等级要高于他们在内部实施的安全等级。        在十年不到的时间里,云计算已从一个有趣的新概念发展成为业界的一大主流市场。业界对云计算未来的期望普遍较高,摩根士丹利预测Amazon网络服 务(AWS)将在2022年突破二百四十亿美元年收入的大关。当然,任何单一一家供应商云计算业务的成功都完全取决于...

    HackerShell 评论0 收藏0
  • 全球知名ssl证书品牌推荐:Symantec、DigiCert、Comodo、GeoTrust、Th

    摘要:全球可信的证书品牌有等。一品牌商家主要有哪些旗下年收购。。这个品牌的是目前全球知名的品牌之一,用的人和企业也不较多。ssl证书品牌有哪些值得推荐的呢?ssl证书是由CA机构颁发的数字认证证书,只要是合法的CA机构比如Comodo、symantec、thawte、digicert这些都可以。   目前,市场上可供选择的SSL证书品牌很多,但并不是所有的品牌都值得信任。如果选择了不可信的...

    GitChat 评论0 收藏0

发表评论

0条评论

wua_wua2012

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<