我如何将此sql-injection-susceptible函数转换为MySQLi中准备好的函数?

问题描述 投票:0回答:2

我有两个可通过sql-injection接受的函数,我设法将第一个函数转换为准备好的函数,但是我看不到如何转换第二个函数。这是原始的第一个:

    function modify($sql, &$id)
    {
        $link = database_link();

        $result = mysqli_query($link, $sql);

        $insertId = mysqli_insert_id($link);

        return mysqli_affected_rows($link);
    }

我翻译成:

    function preparedModify($sql, $types, &$insertId, ...$value)
    {
        $statement = mysqli_prepare(database_link(), $sql);

        $statement->bind_param($types, ...$value);

        $statement->execute();

        $insertId = $statement->insert_id;

        return $statement->affected_rows;
    }

哪个工作,我很满意。这是我需要翻译的第二个功能:

    function select($sql, &$rows)
    {

        $link = database_link();

        $result = mysqli_query($link, $sql);

        $rows = array();

        while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
            $rows[] = $row;
        }

        return mysqli_num_rows($result);
    }

我完全不清楚我作为初学者如何翻译。您能同时帮您分解答案,指出翻译背后的策略是什么?因为我对第一个功能的策略只是谷歌搜索其他功能,所以我设法做到了第一个功能,但是使用相同的方法我对第二个功能一无所获。

php mysqli prepared-statement sql-injection
2个回答
1
投票

如果已安装mysqlnd(以允许使用mysqli_stmt::get_result),则更改可能非常简单。第一部分与mysqli_stmt::get_result相同,然后我们仅使用对preparedModify的调用,其余功能保持不变:

get_result

如前所述,您不需要循环来生成function preparedSelect($sql, $types, &$rows, ...$value) { $statement = mysqli_prepare(database_link(), $sql); $statement->bind_param($types, ...$value); $statement->execute(); $result = $statement->get_result(); $rows = array(); while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) { $rows[] = $row; } return $statement->num_rows; } ,只需使用$rows

mysqli_result::fetch_all

同样,这需要安装本机$rows = $result->fetch_all(MYSQLI_ASSOC); 驱动程序。


1
投票

我不得不承认,运行准备好的SELECT查询有一个怪癖,因为您不能直接从语句中获取熟悉的数组,因此您将需要一个附加的函数调用mysqlnd。但是至少您应该以与其他函数相同的方式开始,因为这是使用预准备语句运行函数的正确方法。

需要注意的几件事

  • 我想每次调用时get_result()都会创建一个新的数据库连接。绝不应该这样,连接只能创建一次。因此,首先创建它,然后将database_link()变量传递到所有函数调用中。
  • 通过参数返回函数的结果是丑陋且不可读的,由于这些原因,人们对此并不满意。而且您不必返回行计数-毫无意义,因为您可以始终使用$link来获取计数。
  • 将单独的变量放入函数调用非常不方便,我很难学到。而是以数组形式放置它们。这样,您将可以具有单独的变量或已经包含所有必需数据的单个变量。

基于我们的count($rows),我们将创建一个易于使用和阅读的程序,

Mysqli helper function

0
投票

我完全同意这里的先前建议。

但是首先:这是我认为您应该使用的prepareSelect()(如果您不想关心这里提到的所有其他事情):

function select($link, $sql, $values = [], $types = '')
{
    if (!$values) {
        $result = $link->query($sql);
    } else {
        $types = $types ?: str_repeat("s", count($values));
        $stmt = $mysqli->prepare($sql);
        $stmt->bind_param($types, ...$values);
        $stmt->execute();
        $result = $stmt->get_result();
    }
    return $result->fetch_all(MYSQLI_ASSOC);   
}

$link = database_link();
$rows = select($link, "SELECT * FROM employees WHERE salary > ?", [$gross]);
if ($rows) {
    // you don't actually need even a count() call
}

另外一件事:我认为您正在混合使用面向对象的样式和过程样式

代替

function preparedSelect($sql, &$rows)
{
    $mysqli = database_link();
    $statement = $mysqli->prepare($sql);
    $statement->execute();

    $rows = $statement->get_result()->fetch_all(MYSQLI_ASSOC);

    return $statement->get_result()->num_rows;
}

应该看起来像这样(面向对象)

$mysqli = database_link();
$statement = mysqli_prepare(database_link(), $sql);
$statement->bind_param($types, ...$value);
© www.soinside.com 2019 - 2024. All rights reserved.