【问题标题】:Is using PHP's Reflection Class to execute MySQL queries secure?使用 PHP 的反射类执行 MySQL 查询是否安全?
【发布时间】:2015-10-07 20:57:00
【问题描述】:

背景

我一直在从头开始开发内容管理系统。出于经验原因,它主要是从头开始开发的,但也将在以后使用。

我开发了一个 DatabaseManager 类,它扩展了 PHP 中的 mysqli 类。我正在使用它进行 MySQL 查询和连接。我开发的一个函数传递了 SQL 查询字符串(它是参数化的),后跟一个要替换的正确值的数组。

TL;DR

长话短说,我使用ReflectionClass 将参数绑定到SQL 查询并执行。我很好奇这是否是一种安全的方法,还是有另一种最适合的方法?

方法

这是DatabaseManager::do_query() 方法:

function do_query($sql, $values){
    if(!isset($this->connect_error)){
        $num_vals = count($values);
        $i = 0;
        $type = "";
        while($i < $num_vals){
            if(is_int($values[$i]) == true)
                $type .= "i";
            elseif(is_string($values[$i]) == true)
                $type .= "s";
            $i++;
        }

        $i = 0;
        while($i < $num_vals){
            $values2[$i] = &$values[$i];
            $i++;
        }
        $values2 = array_merge(array($type), $values2);

        $expr = $this->prepare($sql);
        if($expr != false){
            $ref = new ReflectionClass('mysqli_stmt');
            $method = $ref->getMethod("bind_param");            
            $method->invokeArgs($expr, $values2);

            $expr->execute();
            return "Success";
        }else{
            $error_string = "Error: Query preparation resulted in an error. ";
            $error_string .= $this->error;
            __TGErrorHandler(TG_ERROR_DB_PREP);
            return $error_string;
        }

    }
}

我通过测试没有遇到任何直接错误,而且它似乎可以抵抗 SQL 注入,使用准备好的语句。但是,这种方法的结构是否存在任何潜在问题?

附:我正在以不同的方式处理SELECT 语句。这将主要处理DELETEINSERT 语句。

【问题讨论】:

  • else{} 我不明白你为什么拥有它。
  • 我不确定我是否理解。 @EliasNicolas
  • if($expr != false){} 执行返回,如果$exp 为真,你返回一些东西,如果不是,你总是返回一些东西。您不需要else{}(仅表示else{} 不是里面的东西)但是使用 PDO 更容易。

标签: php mysql class security mysqli


【解决方案1】:

首先,您走在正确的轨道上。只有少数,可能是百分之一的 PHP 用户甚至会想到使用这样一个有用的功能。

接下来,反射对于这个任务来说只是多余的,call_user_func_array() 是一种方法。 Even though it's a little tricky,这是一种直截了当的方法,而反射则不是。

最后,安全。我将删除自动类型检测并将所有参数绑定为字符串。它不会造成任何伤害,而使用您当前的方法,如果您碰巧将数字与数据库中的字符串进行比较,那么数据库可能会返回奇怪的结果。

这个函数的错误处理也是有问题的。

【讨论】:

    【解决方案2】:

    在这里使用反射本身并没有什么不安全的地方,但这完全没有必要。您可以使用call_user_func_array 完成完全相同的事情而无需反射:

    if ($expr !== FALSE) {
        call_user_func_array([$expr, "bind_param"], $values2);
        $expr->execute();
        ...
    

    或者,考虑使用 PDO 代替 mysqli。 PDOStatement::execute() 可以将绑定参数数组作为参数。 (此外,使用 PDO 意味着您的代码可以移植到 MySQL 以外的数据库!)

    【讨论】:

      猜你喜欢
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      • 2012-02-29
      • 2021-10-30
      相关资源
      最近更新 更多