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

时间:2011-12-05 18:18:24

标签: php pdo prepared-statement code-injection parameterized-query

这是代码吗

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 个答案:

答案 0 :(得分:2)

不,你不能绑定那样的运营商。作为一种变通方法,您可以动态创建“基本”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;
}

除此之外,其余的都很好,并且“按照定义”注射防护。

答案 1 :(得分: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");
    }
}

答案 2 :(得分:0)

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

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

在第二种情况下,绑定参数由驱动程序模拟:输入值插入到SQL代码中(具有足够的转义),DBMS接收完整的常规查询。我不确定当前的驱动程序将如何表现(我需要测试它),但即使他们不抱怨无效的SQL,它们迟早会碰壁:SQL运算符不是字符串。< / p>

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

  • 运行重复查询时,您不会从预解析的SQL中受益:如果更改运算符,则更改查询。
  • 您将无法获得安全 SQL代码。你怎么样?

答案 3 :(得分:-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'

:值也可能是另一个列,但是您需要再次嵌套另一个案例构造,就像第一列一样,并且组合现在真的在飙升。

无论如何......只是想表明它可以完成。