Безопасна ли эта функция PDO от инъекции SQL? - PullRequest
0 голосов
/ 21 июля 2010

У меня есть следующая функция вставки.Это безопасно от инъекции 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 ]

4 голосов
/ 21 июля 2010

Единственным разумным способом является использование 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);
2 голосов
/ 21 июля 2010

Если каждый тип столбца имеет значение 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.
1 голос
/ 21 июля 2010

Кстати: когда мы спрашиваем, является ли PDO более безопасным от внедрения SQL, чем какая-либо другая библиотека подключений PHP MySQL, ответ будет НЕТ , когда мы говорим о PDO_MYSQL (не знаю, является ли следующее верно для некоторых других баз данных).

Можно даже утверждать, что PDO менее безопасен и более опасен, чем любая другая библиотека соединений PHP MySQL (ext/mysql и ext/mysqli), поскольку PDO_MYSQL допускает несколько запросов в одном операторе SQL, а ext/mysql полностью останавливает множественные запросы и ext/mysqli имеет функцию sparate mysqli_multi_query().

Я просто пытался найти источники, поддерживающие это утверждение, но единственное, что я нашел:

0 голосов
/ 21 июля 2010

Нет, потому что вы просто выполняете необработанный SQL-запрос с расширением PDO.Я делаю что-то похожее на следующее:

$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);

Я уверен, что вы можете изменить вышеупомянутое, чтобы соответствовать вашей установке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...