我对品葱网的代码进行了安全审计,品葱网的安全性到底如何?

品葱网的安全性一直是许多葱友关心的问题,考虑到感兴趣的读者很多可能没有IT背景,我会尽量用通俗易懂的语言和大家讲解。先说我的结论吧,恐怕要让很多五毛小粉红失望了,那就是品葱网的安全性很高

需要说明的是,一个网站的安全性取决于其依赖的操作系统,网页服务器等方方面面,我这里只对品葱开源的代码的安全性进行讨论。

首先品葱的代码给我的第一印象是,易读而严谨。贴一段代码来说明。这段代码是用户点赞的时候,网站后台的处理逻辑。我相信即使从来没有写过程序的人,在看完代码之后也知道程序大概在做什么。

public function agree_action()
{
    if (!$this->user_info['permission']['vote_agree'])
    {
        H::ajax_json_output(AWS_APP::RSM(null, '-1', AWS_APP::lang()->_t('你的声望还不够')));
    }

    if (!check_user_operation_interval('vote', $this->user_id, $this->user_info['permission']['interval_vote']))
    {
        H::ajax_json_output(AWS_APP::RSM(null, '-1', AWS_APP::lang()->_t('操作过于频繁, 请稍后再试')));
    }

    if (!$this->model('currency')->check_balance_for_operation($this->user_info['currency'], 'currency_system_config_agree'))
    {
        H::ajax_json_output(AWS_APP::RSM(null, '-1', AWS_APP::lang()->_t('你的剩余%s已经不足以进行此操作', get_setting('currency_name'))));
    }

    if (!$this->model('vote')->check_user_vote_rate_limit($this->user_id, $this->user_info['permission']))
    {
        H::ajax_json_output(AWS_APP::RSM(null, '-1', AWS_APP::lang()->_t('今日赞同/反对已经达到上限')));
    }

    $item_info = $this->model('content')->get_thread_or_reply_info_by_id($_POST['type'], $_POST['item_id']);
    if (!$item_info)
    {
        H::ajax_json_output(AWS_APP::RSM(null, -1, AWS_APP::lang()->_t('内容不存在')));
    }

    if ($item_info['uid'] == $this->user_id)
    {
        H::ajax_json_output(AWS_APP::RSM(null, -1, AWS_APP::lang()->_t('不能赞同/反对自己发表的内容')));
    }

    if (!$this->model('vote')->check_same_user_limit($this->user_id, $item_info['uid'], 1))
    {
        H::ajax_json_output(AWS_APP::RSM(null, '-1', AWS_APP::lang()->_t('不能连续赞同同一个用户, 请明天再试')));
    }

    // 恶意行为
    if ($this->model('vote')->get_user_vote_count($this->user_id, null, null, $_POST['type'], $_POST['item_id']) >= 4)
    {
        H::ajax_json_output(AWS_APP::RSM(null, '-1', AWS_APP::lang()->_t('不能反复赞同/反对')));
    }

    set_user_operation_last_time('vote', $this->user_id);

    $this->model('vote')->vote($_POST['type'], $_POST['item_id'], $this->user_id, $item_info['uid'], 1);

    H::ajax_json_output(AWS_APP::RSM(null, 1, null));
}

一段代码的易读性和安全性是正相关的。因为代码越容易读,维护起来的成本越低,越不容易犯错,代码安全性也就越高。除此之外,得益于品葱的MVC架构(Model-View-Controller),使整体的代码逻辑清晰的结合起来,极大提高整体代码的易读性。这里涉及到了代码抽象,易读的代码一定具有良好抽象。打个比方,我们在开车的时候,并不需要操心汽车的引擎是怎么运转的,我们只要踩好油门,控制方向盘就可以了。至于引擎具体怎么运转我们不用操心,汽车会帮我们去控制引擎。如果开车的时候还要考虑引擎怎么控制,那我们开车也太累了,也容易翻车。这里油门就是对引擎的一层抽象。代码也是一样的。当你点赞的时候,程序会对数据库进行写入操作。但是在Contoller看来,他并不需要知道具体使用何种方式去操作数据库。他只要把他知道的数据传给Model,让Model去操心就好了。这样极大减少了代码的复杂度,提高了易读性。总之代码的易读性是衡量代码好坏,和安全性高低的重要指标之一,我认为这方面品葱是做的很不错的。

除了易读,还有严谨。可以看到,这段程序90%以上的代码都在做各种验证检查,只有最后几行是操作数据库给相应的内容增加点赞数并返回结果。如果没有这90%多的检查,网站也能运行,用户也能点赞,但是各种恶意刷赞就无法避免。这也是区分“玩具网站“和专业网站的重要标准之一。而这种强度的验证,品葱的代码里比比皆是,代码的严谨性可见一斑。

品葱代码的严谨还体现在对各种用户可控变量的检查。何为用户可控变量?简单来说当用户对网站发起请求的过程中会传递各种参数,而这些参数用户是可以修改的。还是以点赞为例。当用户点赞的时候,浏览器会发起请求,告诉品葱服务器,“我要给【XXX】文章点赞”。这里的【XXX】就是用户可以控制的变量。如果不进行验证就有可能出现以下情景:【阿葱啊,帮我给XXX文章点赞,等等,我改变主意了,还是给我管理员权限好了】文章点赞

对于像品葱这种开源的网站,没有严格检验的可控变量一定是黑客的最爱,这也是我代码审计的重点关注对象。通过这几天的审计,在品葱代码里出现的大概900多个用户可控变量中(包括重复的在内),我没有发现一个不受检验的。感觉到品葱就像对用户传来的东西带有深深戒心的小菇凉。这就对了,现在外面坏叔叔很多,要学会保护好自己。咳咳,总而言之,要给品葱点个赞。

夸了品葱这么多的优点,接下来说说我认为品葱在安全性上还可以做得更好的地方。

葱友们知道,品葱是根据开源的wecenter二次开发来的。在wecenter中有一个对数据库延迟更新的设计。这个特性设计的初衷是为了减少用户等待时间,将不太重要的数据更新延后,其实现的方式是通过析构函数去执行数据库写入。我个人非常不喜欢这个设计。因为他可能引入一个巨大的安全隐患。

/**

* Model 类析构, 执行延迟查询

*/

public function __destruct()
{
    $this->master();

    foreach ($this->_shutdown_query AS $key => $query)
    {
        $this->query($query);
    }
}

可以看到在这段代码中,query没有经过任何校验,没有任何限制,直接被数据库执行。你可能会说这个query用户不可控,没有必要检验。确实,一般情况下是这样的。但是如果我能够构造一个带有shutdown_query属性的对象呢? 其实这个特性已经作为攻击链的重要一环被发布在网上了。具体网址我就不放上来了,大家有兴趣可以去搜索wecenter反序列化漏洞。最先发现这个漏洞的作者提出的修复方法是删除app/account/ajax.php下名为synch_img的action。品葱的代码里面没有这个action,但是不是就一定高枕无忧了呢?删除了有漏洞的action,确实从入口上堵住了,但是你能保证没有其他还没被发现的入口吗?所以我认为这个解决方法对一般网站是够了,但像品葱这种特殊的网站,应该要做到更进一步,从根源上解决这个问题。在此我提出几点可能的改进思路。

  1. 直接拿掉这个延迟更新特性。为了用户访问快那么一点,引入一个可能带来风险功能,尤其对于品葱而言,是否值得?干脆直接拿掉,这也是最容易实现,最稳的方法。
  2. 使用其他方法去提高用户访问速度,比如使用redis缓存,异步更新等方式来达到相同的效果,而不要用这么hack的方法。这缓存等方式提高访问速度也是主流的做法,缺点是实现和维护成本较高。
  3. 继续保留这个特性,但是query要将上限制。因为方法2的实现维护成本问题,而又想用户访问等待时间尽可能的短,那就加限制吧。比如设定只有特定的query语句才能运行。


正如我前面所讲,网站的安全性涉及到方方面面,网页应用安全只是其中一环。大家千万不要小看顶尖黑客的实力。他们的超高的创造力和不达目标不放弃的执着,远超常人想象。而我们能做的就是通过层层安全防护,去提高他们入侵的成本,同时减少他们入侵所造成的破坏。

我认为品葱网要长久稳定的运行,从技术上讲,以下几点非常关键。

  1. 如果黑客拿到品葱服务器的最高权限,能不能做到保证让黑客找不到任何有用信息从而溯源找到自己?
  2. 如果黑客拿到权限并登入服务器,站长能不能及时发现?
  3. 如果数据库被删掉,服务器被清空,站长能不能快速恢复网站服务?


以上都是基于最坏的情况下思考如何减少黑客行为带来的破坏。而为了实现这些目标,我认为现代化的运维和监控是非常重要,简单得说就是减少一切对服务器的人为操作,使用程序去管理程序。所谓的现代化运维一个很重要的体现在对代码的快速自动的部署上。比如说以前程序员需要登入服务器,去手动更新应用程序。如果有了自动化运维的帮助,这些重复动作就可以避免。这样不仅减少出错的可能,也提高了安全性。

我相信品葱的站长敢把品葱的源码开源,说明他是有信心可以驾驭得住的,而且也一定考虑过最坏的情况。这里我只是抛砖引玉,希望广大葱友集思广益,让品葱变得更加的安全。

最后说一句,有一个可以发表文章而不被五毛粉红打扰的环境是不容易的,希望大家且行且珍惜。祝品葱发展得越来越好!
技术是一方面,我觉得品葱最大的价值是其严谨的用户标签、人工审查制度以及管理员坚决的执行力,绝对不给五六七毛一丝丝可乘之机,就连我自己的很多帖子每次都是管理员手动给我移到正确的分区(羞愧)。
品葱的代码修饰器太丑了,没有语法着色功能。这样会失去技术类用户的
v2ex难民只能去reddit了

/**

* Model 类析构, 执行延迟查询

*/

public function __destruct()
{
    $this->master();

    foreach ($this->_shutdown_query AS $key => $query)
    {
        $this->query($query);
    }
}



能别拿着一套n年前的代码整天审计了吗?也不看看里面的库都是哪年的,我都没想到这套代码能用这么久。反正早不维护了,拿来二次开发就开发吧,后来人引进的漏洞请别甩到我们头上。

这套代码确实不优雅,我们开发的时候 ORM 都不流行,拼接字符串、序列化还是主流。不过真没那么多严重的漏洞,不然当时一堆站都被注入了。
 俺在墙外 几年都不去沦陷区一次 不过还是谢谢op
攻击者如果比较菜,可能就止步于用户可控变量了,楼主这还讨论了利用wecenter漏洞的可能性,真的很用心,特别赞。
fkgcd9901 观察 FREEDOM IS NOT FREE. 行动改变中国
有没有挂马的可能性?如果挂木马了,那么诸位 IP地址都被曝光了,所以以后还是通过VPN上敏感网站比较靠谱

要发言请先登录注册