How to prevent mysql injection when using mysql IN clause without activeRecord in Yii?

南楼画角 提交于 2019-12-24 18:04:36

问题


I have an array with ids that I get from client. And I want use those ids in my sql query with IN clause. But this query goes on a table that has no model. So there is no active record (criteria) query possible.

** Table userTasks **

--------------------
| idUser | idTasks |
---------+----------
|    1   |    1    |
---------+----------
|    1   |    2    |
---------+----------
|    1   |    3    |
---------+----------

First approach does not work because params are always considered as strings. So :tasks is a string '1,2,3' instead of a comma separated list of ids:

$sql = 'SELECT COUNT(*) AS matches 
        FROM userTasks 
        WHERE idUser = :idUser 
          AND idTask IN (:tasks)';
$result = Yii::app()->db->createCommand($sql)
  ->queryRow(true,[
    ':idUser' => $idUser,
    ':tasks' => implode(',', $tasks)]); //$tasks is a simple array of ids [1,2,3]

So my workaround:

foreach($tasks as $task) //$tasks is a simple array of ids [1,2,3]
{
  $inTasks[] = (int) $task;
}

$sql = 'SELECT COUNT(*) AS matches 
        FROM userTasks 
        WHERE idUser = :idUser 
        AND idTask IN (' . implode(',', $inTasks . ')';
$result = Yii::app()->db->createCommand($sql)
  ->queryRow(true,[':idUser' => $idUser]);

回答1:


Having come across this problem a few times in my projects I have come-up with the following Yii work-around using CDbCriteria which is a little hacky, but gives the security of param count matching.

I would also use queryScalar() in this instance to get the result directly.

When applied to your example my code would be:

$idUser = 1;
$tasks = array(1,2,3);
$criteria = new CDbCriteria();
$criteria->addInCondition('idTask',$tasks);

$sql = '
  SELECT COUNT(*) matches
    FROM userTasks
   WHERE idUser = :idUser
     AND '.$criteria->condition;

$command = Yii::app()->db->createCommand($sql);
$command->bindValue('idUser',$idUser);
$command->bindValues($criteria->params);
$result = $command->queryScalar();



回答2:


For preventing SQL injection in Yii IN clause we need to bind parameters in IN clause, Yii CDB criteria queries don't have this functionality in built. so you can use below code.

$products_ids = array(234,100,405,506);

map the array for binding

$in_query = implode(',', array_fill(0, count($products_ids), '?'));

Prepare the commadn object for select

$command = Yii::app()->db->createCommand()
                 ->select('product_id, product_name, product_image, product_price')
                 ->from('products')
                 ->where('product_id IN(' . $in_query . ')');

bind the parameters

foreach ($products_ids as $k => $product_id){
     $command->bindValue(($k+1),$product_id,PDO::PARAM_INT);
}

get the result

$products = $command->queryAll();


来源:https://stackoverflow.com/questions/24805247/how-to-prevent-mysql-injection-when-using-mysql-in-clause-without-activerecord-i

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!