1

这是代码吗

class opinion
{
   private $dbh;
   var $opinionid,$opinion,$note,$actorid,$dateposted;
   var $isnew=FALSE;
   function loadby($column,$value,$operator="="){
       $dbh = new PDO(I deleted parameters here);
       $statement=$dbh->prepare("select * from fe_opinion where :column :operator :value");
       $statement->bindParam(":column", $column);
       $statement->bindParam(":value", $value);
       $statement->bindParam(":operator", $operator); //UNSURE, DOUBTFUL
       $statement->bindColumn("opinionid", $this->opinionid);
       $statement->bindColumn("opinion", $this->opinion);
       $statement->bindColumn("note", $this->note);
       $statement->bindColumn("actorid", $this->actorid);
       $statement->bindColumn("dateposted", $this->dateposted);
       $statement->fetch();
       return $statement->rowCount(); //please be 1
   }
}

注射安全吗?

       $statement->bindParam(":operator", $operator); //UNSURE, DOUBTFUL

我可以将参数绑定到 PDO 语句作为比较运算符吗?

4

4 回答 4

3

不,您不能像那样绑定运算符。作为一种解决方法,您可以动态创建“基本”SQL 查询并使用操作员白名单(这是非常合适的)来保持安全免受注入:

function loadby($column,$value,$operator="="){ 
   $dbh = new PDO(...); 
   $operator = getOperator($operator);
   if(!$operator) {
       // error handling
   }
   $statement=$dbh->prepare("select * from fe_opinion where :column $operator :value");
   // the rest like you already do it
} 

function getOperator($operator) {
   $allowed_ops = array('=', '<', '>'); // etc
   return in_array($operator, $allowed_ops) ? $operator : false;
}

除此之外,其余的都很好并且“根据定义”是防注入的。

于 2011-12-05T18:25:33.663 回答
0

根据 DBMS 和 PHP 驱动程序,准备好的语句可以是“真实的”或模拟的。

在第一种情况下,绑定参数由 DBMS 直接处理。在这种情况下,将运算符作为参数处理可能会触发语法错误。SQL 解析器将在不查看参数的情况下分析查询,并且不会找到有效的 SQL 代码来处理。

在第二种情况下,驱动程序模拟绑定参数:输入值被插入到 SQL 代码中(有足够的转义),并且 DBMS 接收到完整的常规查询。我不太确定当前驱动程序的行为方式(我需要对其进行测试),但即使他们不抱怨无效的 SQL,他们迟早会碰壁:SQL 运算符不是字符串。

现在,有一天会实现一个很好的功能吗?我怀疑它是:

  • 运行重复查询时,您不会从预解析的 SQL 中受益:如果您更改运算符,就会更改查询。
  • 你不会得到安全的 SQL 代码。你怎么能?
于 2011-12-05T18:41:08.333 回答
0

正如评论中提到的,我认为不可能逃脱运营商并让它按预期工作。生成的查询可能类似于:

'column' '=' 'value';

您无需转义运算符以避免注入攻击,您可以在将运算符附加到字符串之前对其进行验证,请考虑:

class opinion
{
    $validOperators = array('=', '>=', '>', '=<', '<');

    function loadby($column,$value,$operator="=") {

        // Validate operator
        if (!in_array($operator, self::$validOperators)) {
            throw new Exception('Invalid $operator ' . $operator . ')';
        }

        $statement=$dbh->prepare("select * from fe_opinion where :column " . $operator . " :value");
    }
}
于 2011-12-05T18:26:21.240 回答
-2

你实际上可以做到。sql变得更加复杂。根据组合的数量,sql 会变得非常庞大。但是,有时当只有几个选择时,它很好。

select * 
  from someTable

where (case :column
       when 'age' then (case :operator
                               when '>' then age > :value
                               when '<' then age < :value
                        end)
       when 'price' then (case :operator
                               when '>' then price > :value
                               when '<' then price < :value
                        end)
      end)

  and someOtherCol = 'foo'

:value 也可以是另一列,但是您需要再次嵌套另一个 case 构造,例如第一列,并且组合现在真的飙升。

无论如何......只是想表明它可以做到。

于 2011-12-05T19:13:04.187 回答