欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ThinkPHP的model控制不严格。可能引起严重安全问题。

程序员文章站 2022-03-02 19:01:19
...

最近review应该TP写的项目的时候。无意看到TP最底层的model控制不是很严格。使用不当即可导致很严重的安全问题。

这里简单说一下,特别是新手需要特别注意。

文件位置在ThinkPHP\Lib\Core\model.class.php

/**
     * 创建数据对象 但不保存到数据库
     * @access public
     * @param mixed $data 创建数据
     * @param string $type 状态
     * @return mixed
     */
     public function create($data='',$type='') {
        // 如果没有传值默认取POST数据
        if(empty($data)) {
            $data   =   $_POST;
        }elseif(is_object($data)){
            $data   =   get_object_vars($data);
        }
        // 验证数据
        if(empty($data) || !is_array($data)) {
            $this->error = L('_DATA_TYPE_INVALID_');
            return false;
        }

        // 检查字段映射
        $data = $this->parseFieldsMap($data,0);

        // 状态
        $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT);

        // 检测提交字段的合法性
        if(isset($this->options['field'])) { // $this->field('field1,field2...')->create()
            $fields =   $this->options['field'];
            unset($this->options['field']);
        }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) {
            $fields =   $this->insertFields;
        }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) {
            $fields =   $this->updateFields;
        }
        if(isset($fields)) {
            if(is_string($fields)) {
                $fields =   explode(',',$fields);
            }
            // 判断令牌验证字段
            if(C('TOKEN_ON'))   $fields[] = C('TOKEN_NAME');
            foreach ($data as $key=>$val){
                if(!in_array($key,$fields)) {
                    unset($data[$key]);
                }
            }
        }

        // 数据自动验证
        if(!$this->autoValidation($data,$type)) return false;

        // 表单令牌验证
        if(!$this->autoCheckToken($data)) {
            $this->error = L('_TOKEN_ERROR_');
            return false;
        }

        // 验证完成生成数据对象
        if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据
            $fields =   $this->getDbFields();
            foreach ($data as $key=>$val){
                if(!in_array($key,$fields)) {
                    unset($data[$key]);
                }elseif(MAGIC_QUOTES_GPC && is_string($val)){
                    $data[$key] =   stripslashes($val);
                }
            }
        }

        // 创建完成对数据进行自动处理
        $this->autoOperation($data,$type);
        // 赋值当前数据对象
        $this->data =   $data;
        // 返回创建的数据以供其他调用
        return $data;
     }
当参数 $data 为空的时候。直接data为POST数据。

也就意味着只要知道数据库字段(猜到字段名称是一件很任意的事情)。任意字段都是用户可控的?危险就不言而喻了!

一个注册功能。数据库有3个字段username,userpwd,group(0普通用户1管理员)

假如代码这样写

function register(){
    if(D('user')->create() && D('user')->add();){
        echo 'success';
    }else{
        echo 'fail';
    }
}
也就是当用户直接post['group']=1 就自动成为管理员了!

所以建议使用这个方法的时候传入指定的数据。或者对于不需要用户填写的字段进行初始化

function register(){
    D('user')->group = 0;
    if(D('user')->create() && D('user')->add();){
        echo 'success';
    }else{
        echo 'fail';
    }
}

function register(){
    //注意给POST数据进行xss和注入过滤
    $data['userpwd'] = $_POST['userpwd'];
    $data['username'] = $_POST['username'];
    if(D('user')->create($data) && D('user')->add();){
        echo 'success';
    }else{
        echo 'fail';
    }
}
上面2个是比较安全的写法。

另外这个框架在magic_quotes_gpc=off的时候如果不对参数进行单独过滤。是存在入住和xss问题的

看看最上面的代码

// 验证完成生成数据对象
        if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据
            $fields =   $this->getDbFields();
            foreach ($data as $key=>$val){
                if(!in_array($key,$fields)) {
                    unset($data[$key]);
                }elseif(MAGIC_QUOTES_GPC && is_string($val)){
                    $data[$key] =   stripslashes($val);
                }
            }
        }
这里的magic_quotes_gpc=false的时候 是不过进行 stripslashes处理的。也就意味着可能导致xss和注入的发生。当然框架本身没有解决注入的xss的义务。但是你既然写了为嘛不写好的。有误导用户的嫌疑。


最后如果你的项目使用了这个框架,赶紧review一下你的代码吧!


转载于:https://my.oschina.net/qiji2012/blog/165232