使SQL查询安全 - 从$ _POST获取值

时间:2013-09-02 17:49:15

标签: php mysql security pdo

我正在使用此代码更新mysql表中的字段。

foreach ($_POST['changed'] as $SubArray) {
    foreach ($SubArray as $key => $value) {
        if ($key === 'recid') continue;

        $STH = $DBH->prepare("UPDATE clients SET $key = '$value' WHERE id = $SubArray[recid]");
        $STH->execute();
    }    
}

我认为查询中的$key$value$SubArray[recid]等变量非常不安全。有没有办法使这个安全,$_POST没有不需要的代码进入查询?

(无法使用占位符调用列,因为我不知道表中的列名称)

2 个答案:

答案 0 :(得分:0)

使用safeMysql,这是小菜一碟:

include 'safemysql.class.php';
$db = new safeMysql();

$allowed = array('name', 'surname', 'all the fields you want to save');

foreach ($_POST['changed'] as $SubArray)
{
    $insert = $db->filterArray($SubArray, $allowed);
    $db->query("UPDATE clients SET ?u WHERE id = ?s", $insert, $SubArray['recid']);
}
在PDO有缺陷的情况下,你会遇到更多麻烦 首先,您需要自己动手创建一个值列表,因为没有理智的开发人员会逐个更新字段:

function pdoSet($fields, &$values, $source = array()) {
    $set = '';
    $values = array();
    if (!$source) $source = &$_POST;
    foreach ($fields as $field) {
        if (isset($source[$field])) {
            $set.="`".str_replace("`","``",$field)."`". "=:$field, ";
            $values[$field] = $source[$field];
        }
    }
    return substr($set, 0, -2); 
}

现在您可以开始运行更新

$allowed = array('name', 'surname', 'all the fields you want to save');
foreach ($_POST['changed'] as $SubArray)
{
    $set = pdoSet($allowed, $values, $SubArray);
    $sql = "UPDATE clients SET $set WHERE id = :id";
    $stm = $dbh->prepare($sql);
    $values["id"] = $SubArray['recid'];
    $stm->execute($values);
}

回答评论中的问题:

首先,一个不了解他的领域的开发人员是胡说八道。它不可能。像phpmyadmin这样的自由格式应用程序是一种罕见的例外,显然情况并非如此。

毕竟,这是安全问题。 2个危险来自自由形式阵列:

  1. 表中可能存在不允许客户使用的字段。您肯定会重复使用此代码让客户编辑其详细信息。因此,总是知道您必须更新的字段要好得多。
  2. 通过命名占位符进行简单的SQL注入(您可能会注意到它们直接来自用户输入未触及)。
  3. 因此,如果您100%确定不能添加任何人工场 - 您可以省略此检查,但是您将自己置于持续危险之中。无论如何,必须在字段名称上使用str_replace这个东西,而必须使用位置(?)占位符而不是命名的占位符。

答案 1 :(得分:0)

如果您确保$key的值是安全的,那么这将是安全的 。 例如:

$approved = array('fname', 'lname' ,'email');
foreach ($_POST['changed'] as $SubArray) {
    foreach ($SubArray as $key => $value) {
       // if ($key === 'recid') continue; (Since we're using in_array - no need in this line)
         if(in_array($key , $approved))
         {
           //$key is safe: 
               $STH = $DBH->prepare("UPDATE clients SET $key = :value WHERE id = :id");
               $STH->execute(array(':value' => $value , ':id' => $SubArray['recid']));
         }

      }    
}

<强>更新 请注意你在循环中使用循环, 为了提高效率,请考虑更改代码。