这个PDO函数是否可以安全地从sql注入

时间:2010-07-21 11:31:43

标签: php pdo

我有以下插入功能。从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;
}

先谢谢

4 个答案:

答案 0 :(得分:4)

唯一合理的方法是使用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);

答案 1 :(得分:2)

如果每个列类型都是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.

答案 2 :(得分:1)

顺便说一句:当我们询问PDO是否比其他PHP MySQL连接库更安全时,答案是 NO 当我们谈论PDO_MYSQL时(不知道是否对于其他一些数据库,情况如下。

甚至可以反过来论证,PDO不如任何其他PHP MySQL连接库(ext/mysqlext/mysqli)安全且更危险,因为PDO_MYSQL允许多个查询一个SQL语句,ext/mysql完全停止多个查询,ext/mysqli有一个sparate函数mysqli_multi_query()

我只是试图找到支持这种说法的任何来源,但我发现的唯一的事情是:

答案 3 :(得分:-1)

不,因为您只是使用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);

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