这个 PDO 函数可以安全地避免 sql 注入吗

发布于 2024-09-10 14:51:52 字数 755 浏览 8 评论 0原文

我有以下插入功能。 sql注入是否安全?如果不是那么我该如何保证它的安全。

public function insert($postValues, $table){

    $dbh = $this->connect();

    try {
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $fields = implode(array_keys($postValues), ',');
        $values = "'".implode(array_values($postValues), "','")."'"; 
        $insertQuery = 'INSERT INTO '.$table.' ('.$fields.') VALUES (:'.$fields.')';

        $stmt = $dbh->prepare($insertQuery);

        foreach($postValues as $vals) {
            $stmt->execute($vals);
        }

        $message = $sucessMessage;
    }
    catch(PDOException $e){
        $message = $e->getMessage();
    }

    $dbh = null;

    return $message;
}

提前致谢

I have the following insert function. Is it safe from a sql injection. If it isn't then how do I make it safe.

public function insert($postValues, $table){

    $dbh = $this->connect();

    try {
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $fields = implode(array_keys($postValues), ',');
        $values = "'".implode(array_values($postValues), "','")."'"; 
        $insertQuery = 'INSERT INTO '.$table.' ('.$fields.') VALUES (:'.$fields.')';

        $stmt = $dbh->prepare($insertQuery);

        foreach($postValues as $vals) {
            $stmt->execute($vals);
        }

        $message = $sucessMessage;
    }
    catch(PDOException $e){
        $message = $e->getMessage();
    }

    $dbh = null;

    return $message;
}

Thanks in Advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不打扰别人 2024-09-17 14:51:53

如果每个列类型都是 PDO::PARAM_STR,那么使用 PDOStatement::execute。但是,如果列类型不同,则在使用 PDOStatement::bindParam

接受看似用户输入的表名和列名并不是一个好主意。如果表名或列​​名不正确,查询将会失败,但您需要非常小心,以确保表名和列名可以安全使用。以下示例在执行任何 SQL 之前根据白名单检查表名和列名:

function insert($postValues, $table) {
    $dbh = $this->connect();

    // Create a simple whitelist of table and column names.
    $whitelist = array('my_table' => array('col1', 'col2', 'col3'));

    // Check if the table name exists in the whitelist.
    if(!array_key_exists($table, $whitelist)) {
        exit("$table is not a valid table name.\n");
    }

    // Count the number of columns that are found in the whitelist.
    $cols = count(
        array_intersect(
            $whitelist[$table],
            array_keys($postValues)));

    if($cols !== count($postValues)) {
        exit("One or more invalid column names have been supplied.\n");
    }

    // Create a comma separated list of column names.
    $columns = implode(', ', array_keys($postValues));
    // Create a comma separated list of unnamed placeholders.
    $params = implode(', ', array_fill(0, count($postValues), '?'));
    // Create a SQL statement.
    $sql = "INSERT INTO $table ($columns) VALUES ($params)";

    // Prepare the SQL statement.
    $stmt = $dbh->prepare($sql);
    // Bind the values to the statement, and execute it.
    return $stmt->execute(array_values($postValues));
}

echo insert(
    array(
        'col1' => 'value1',
        'col2' => 'value2',
        'col3' => 'value3'),
    'my_table');

// 1

echo insert(
    array(
        'col1' => 'value1',
        'col2' => 'value2',
        'col3' => 'value3'),
    'unsafe_table');

// unsafe_table is not a valid table name.

echo insert(
    array(
        'col1' => 'value1',
        'col2' => 'value2',
        'unsafe_col' => 'value3'),
    'my_table');

// One or more invalid column names have been supplied.

If each column type is a PDO::PARAM_STR, then it is fairly simple to bind your parameters to unamed paramter markers using PDOStatement::execute. However, if the column types vary, then you need to specify the column type for each column when you bind to it with PDOStatement::bindParam.

Accepting table and column names from what appears to be user input, is not a good idea. The query will fail if the table or column names are incorrect, but you need to be very careful to ensure that the table and column names are safe to use. The following example checks the table and column names against a whitelist, prior to executing any SQL:

function insert($postValues, $table) {
    $dbh = $this->connect();

    // Create a simple whitelist of table and column names.
    $whitelist = array('my_table' => array('col1', 'col2', 'col3'));

    // Check if the table name exists in the whitelist.
    if(!array_key_exists($table, $whitelist)) {
        exit("$table is not a valid table name.\n");
    }

    // Count the number of columns that are found in the whitelist.
    $cols = count(
        array_intersect(
            $whitelist[$table],
            array_keys($postValues)));

    if($cols !== count($postValues)) {
        exit("One or more invalid column names have been supplied.\n");
    }

    // Create a comma separated list of column names.
    $columns = implode(', ', array_keys($postValues));
    // Create a comma separated list of unnamed placeholders.
    $params = implode(', ', array_fill(0, count($postValues), '?'));
    // Create a SQL statement.
    $sql = "INSERT INTO $table ($columns) VALUES ($params)";

    // Prepare the SQL statement.
    $stmt = $dbh->prepare($sql);
    // Bind the values to the statement, and execute it.
    return $stmt->execute(array_values($postValues));
}

echo insert(
    array(
        'col1' => 'value1',
        'col2' => 'value2',
        'col3' => 'value3'),
    'my_table');

// 1

echo insert(
    array(
        'col1' => 'value1',
        'col2' => 'value2',
        'col3' => 'value3'),
    'unsafe_table');

// unsafe_table is not a valid table name.

echo insert(
    array(
        'col1' => 'value1',
        'col2' => 'value2',
        'unsafe_col' => 'value3'),
    'my_table');

// One or more invalid column names have been supplied.
深海夜未眠 2024-09-17 14:51:53

顺便说一句:当询问 PDO 是否比其他 PHP MySQL 连接库更安全地避免 SQL 注入时,当我们谈论 PDO_MYSQL 时,答案是 NO(不知道是否以下对于其他一些数据库也是如此)。

人们甚至可以反过来说,PDO 比任何其他 PHP MySQL 连接库(ext/mysqlext/mysqli)更不安全且更危险,因为 PDO_MYSQL 允许在一个 SQL 语句中进行多个查询,而 ext/mysql 完全停止多查询,并且 ext/mysqli 有一个独立的函数 mysqli_multi_query()

我只是试图找到任何来源来支持这个声明,但我发现的唯一的东西是:

By the way: when asking if PDO is safer from sql injection than some other PHP MySQL connection library, the answer is NO when we talk about PDO_MYSQL (don't know if the following is true for some other databases).

One could even argue the other way round, PDO is less secure and more dangerous than any other PHP MySQL connection library (ext/mysql and ext/mysqli) because PDO_MYSQL allows for multiple queries in one SQL statement while ext/mysql stops multi-queries completely and ext/mysqli has a sparate function mysqli_multi_query().

I just tried to find any sources to support this statement, but the only things I found are:

演出会有结束 2024-09-17 14:51:53

不,因为您只是使用 PDO 扩展执行原始 SQL 查询。我做了类似以下的事情:

$fields = array();
$values = array();

foreach ($_POST as $field => $value) {
    $fields[] = $field;
    $values[] = $this->pdo->quote($value);
}

$fields = implode(',', $fields);
$values = implode(',', $values);

$sql = "INSERT INTO $table ($fields) VALUES ($values)";
$res = $this->pdo->query($sql);

我确信您可以修改上面的内容以适合您的设置。

No, because you're just executing a raw SQL query with the PDO extension. I do something similar to the following:

$fields = array();
$values = array();

foreach ($_POST as $field => $value) {
    $fields[] = $field;
    $values[] = $this->pdo->quote($value);
}

$fields = implode(',', $fields);
$values = implode(',', $values);

$sql = "INSERT INTO $table ($fields) VALUES ($values)";
$res = $this->pdo->query($sql);

I'm sure you can modify the above to fit your set-up.

一江春梦 2024-09-17 14:51:52

唯一明智的方法是使用 PDO::prepare 带参数(参见手册中的示例)。此外,字段名称应取自可信来源,即不是用户。这样,您就可以从受信任的组件构建查询字符串:

function insert ($table, $fields, $data)
{
    $field_names = implode (", ", $fields);                      # "a, b"
    $values = ":" . implode (", :", $fields);                    # ":a, :b"
    $query = "INSERT INTO $table($field_names) VALUES($values)";
    $sth = $pdo->prepare ($query);

    foreach ($data as $row) {
        # Here you can even remove "bad" keys from $row
        $sth->execute ($row);
    }
}

$fields = array ('a', 'b'); # those are hard-coded in application
$data = array (             # those come from user
    array ('a'=>'Apple', 'b'=>'Bean'),
    array ('a'=>'Avocado', 'b'=>'Blueberry', '); DELETE FROM fruits; -- '=>'evil'),
);
insert ('fruits', $fields, $data);

The only sane way is to use PDO::prepare with parameters (see example in manual). Moreover, field names should be taken from trusted source, i.e. not user. This way, you build your query string from trusted components:

function insert ($table, $fields, $data)
{
    $field_names = implode (", ", $fields);                      # "a, b"
    $values = ":" . implode (", :", $fields);                    # ":a, :b"
    $query = "INSERT INTO $table($field_names) VALUES($values)";
    $sth = $pdo->prepare ($query);

    foreach ($data as $row) {
        # Here you can even remove "bad" keys from $row
        $sth->execute ($row);
    }
}

$fields = array ('a', 'b'); # those are hard-coded in application
$data = array (             # those come from user
    array ('a'=>'Apple', 'b'=>'Bean'),
    array ('a'=>'Avocado', 'b'=>'Blueberry', '); DELETE FROM fruits; -- '=>'evil'),
);
insert ('fruits', $fields, $data);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文