1

这是有问题的 PHP 函数:

//Get data associated with $criteria from db
function getUserData($criteria, $value) {
    //obtain user data from db based on $criteria=$value
    global $pdo;
    //echo $criteria . " " . $value;
    try {
        $sql = 'SELECT id, first, last, email, userid FROM users WHERE :criteria= :value';
        //var_dump($sql);
        $st = $pdo->prepare($sql);
        $st->bindValue(':criteria', $criteria);
        $st->bindValue(':value', $value);
        $st->execute();
    }
    catch (PDOException $ex) {
        $error = "Failed to obtain user data.";
        $errorDetails = $ex->getMessage();
        include 'error.html.php';
        exit();
    }
    $row = $st->fetch();
    //var_dump($row);
        if ($row)
        {
            $userdata = array();
            $userdata['id'] = $row['id'];
            $userdata['first'] = $row['first'];
            $userdata['last'] = $row['last'];
            $userdata['email'] = $row['email'];
            $userdata['userid'] = $row['userid'];
            return $userdata;
        }
        return FALSE;
}

我使用此函数返回与其中特定列关联的整行数据。

当在它的当前状态下使用时,通过这样的调用getUserData("email", "John_Stewart_2013"),它返回 false,这意味着一个空结果,而相同的查询在 MySQL CLI 中运行良好。

另一方面,如果我将查询字符串 $sql 替换为:

$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria='$value'";

并注释掉 bindValue 调用,PHP 中的每一件事都运行良好,并且查询按需要返回。

但问题是,这些函数参数是用户提交的表单数据,这意味着该解决方案容易受到 SQL 注入的攻击。

第一个查询表单有什么问题?

4

1 回答 1

2

bindValue恐怕你不能使用列名。

如果您考虑一下准备好的语句是什么,这应该会变得更加明显。基本上,当您使用数据库服务器准备语句时,它会预先为查询创建一个执行计划,而不是在运行查询时生成它。这使得它不仅更快而且更安全,因为它知道它的去向,以及它将使用的数据类型以及将要输入的数据类型。

如果列/表名可以以任何方式绑定,它就无法生成这个执行计划,使得整个准备好的语句的想法有些多余。

最好的方法是使用这样的混合查询:

$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria = :value";

无论如何,我希望该$criteria专栏不是完全免费的形式。如果是这样,您最好将其限制为一组特定的允许选项。一个简单的方法是构建一个允许列的数组,并检查它是否有效in_array,如下所示:

$allowed_columns = array('email', 'telephone', 'somethingelse');
if (!in_array($criteria, $allowed_columns))
{
    $error = "The column name passed was not allowed.";
    $errorDetails = $ex->getMessage();
    include 'error.html.php';
    exit;
}
于 2013-01-27T19:24:57.640 回答