偶然发现的bug————越权访问漏洞追溯

因为经常需要做一些小的demo,所以掌握一个快速开发框架是十分重要的,我比较习惯使用yii2,而就在写demo的过程中,最后使用脚本自动化测试的时候,偶然间发现了不登陆竟然也可以执行逻辑代码,这也就是这篇文章的起源。

 

简单介绍

大家都知道,框架基本都是基于mvc框架的,yii2也不例外,每个框架都有自己封装好的访问控制代码组件,很多人(也包括我自己)在使用的时候,是不会去具体查看究竟是怎么实现的,这也就可能会导致版本更替,或者版本更新了以后,还按照默认写法来做访问控制,最终导致了越权漏洞的产生。
在yii中,所有的逻辑代码都写在控制器中,而每一个操作又叫动作,所以在yii中,一个控制器的大概结构就是:

class SiteController extends Controller
{
    public function actionIndex()
    {
        return $this->render('index');
    }

    public function actionLogin()
    {
        .........
        return $this->render('index');
    }
}

 

csrf的防御

为什么要先讲讲csrf的防御呢?因为我了解访问控制,就是从这里开始的。前面的几篇文章分析的cms,也有很多都没有实现csrf校验,也算是提供一个比较好的实现方法。

在所有使用yii开发的系统,默认都是开启了csrf token防御验证的,而具体实现这个校验的途径,就是使用了一个叫做beforeacton的特殊动作,这个动作会在该控制器的任意动作执行之前执行。
我们具体跟进看一下所有控制器的父类里面的实现:
可以看到,这里csrf有两个关键的点:

$this->enableCsrfValidation
!Yii::$app->getRequest()->validateCsrfToken()

上面的是配置,开发者是可以在控制器当中关闭配置来关闭csrf验证的,下面则是验证csrf token的函数,我们继续跟进一下:
通过简单的查看,可以看到具体的实现代码,这样就可以实现对开发者和访问者都透明化的处理,既不会干扰开发者写正常的逻辑代码,也不会影响访问者的操作,可以说是比较经典的实现csrf校验的方法。

 

访问控制的实现

yii2.0.3版本之前,如果控制器的所有动作都是需要登陆的,那就可以在beforeaction中直接写上控制代码,例如:
但是就是这样的默认写法,在前几天测试的时候却出现了问题。

简单测试

我们简单写一个demo测试一下,其中的actionbeforeaction如下图:
然后尝试访问一下site/test这个动作,按理说这个时候是不会显示123的,应该渲染index所对应的模板文件
但是实际情况确实仍旧会打印出来123,这就说明test这个动作还是执行了,越权漏洞也就产生了,如果控制器内部有一些危险的动作,加上这个越权漏洞危害还是比较巨大的。

资料查找

经过在github上的搜索,发现这个问题在issue中是有人提到过的,并且官方给出了解决方案。

对比分析

可以看到,解决方案是在redirect后面紧接上执行send函数,那我们就来看一下现在这两个函数:


根据大概的函数名,可以看出来redirect函数只是向浏览器发送了一个302的响应码,这其实在安全中就和只做了前端验证是一样的操作,所以是非常危险的,那我们继续追踪一下send函数,他又是怎么弥补这个问题的呢?
send函数实现了强制发送302跳转的功能,并且在最后关闭了当前的连接,这样就能确保越权不在产生,其实总结一下:

redirect => echo "<script>window.location.href=xxx;</script>";
redirect+send => echo "<script>window.location.href=xxx;</script>";die();

就大概相当于这样,所以道理是非常浅显易懂的,但是由于封装了很多层,所以可能不是很好看出来。

 

后记

所以不论是在开发或者是在做安全的过程中,重视开发文档都是非常重要的,严格的实现协议,严格的按照开发文档实现逻辑,会减少很多漏洞的产生。

(完)