2012-07-03 2 views
41

Я использовал функцию mysqli_stmt_bind_param несколько раз. Однако, если я разделяю переменные, которые я пытаюсь защитить от внедрения SQL, я сталкиваюсь с ошибками.Могу ли я параметризовать имя таблицы в подготовленном заявлении?

Вот некоторые примеры кода:

function insertRow($db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol) 
{ 
    $statement = $mysqli->prepare("INSERT INTO " .$new_table . " VALUES (?,?,?,?,?,?,?);"); 
    mysqli_stmt_bind_param($statment, 'sssisss', $Partner, $Merchant, $ips, $score, $category, $overall, $protocol); 
    $statement->execute(); 
} 

Можно ли каким-то образом заменить .$new_table. конкатенации с другим утверждением знак вопроса, сделать еще одно заявление параметров связывания, или добавить на существующий для защиты от инъекции SQL?

Как это или какая-то форма этого:

function insertRow($db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol) 
{  
    $statement = $mysqli->prepare("INSERT INTO (?) VALUES (?,?,?,?,?,?,?);"); 
    mysqli_stmt_bind_param($statment, 'ssssisss', $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol); 
    $statement->execute(); 
} 
+2

Нет, параметризованный запрос не просто отбрасывает значения параметров в строку запроса, но и предоставляет РСУБД параметризованный запрос и параметры отдельно. Но такой запрос не может иметь имя таблицы или имя поля в качестве параметра. Единственный способ сделать это - динамически закодировать имя таблицы в строке запроса, как и вы уже сделали. Если эта строка потенциально открыта для атаки, вы должны сначала ее проверить; например, против списка белых списков допустимых таблиц. – MatBailie

+0

Использование расширения mysqli безопасно, вперед! Но не забывайте санировать и проверять все свои строки .. если имя таблицы или поля или что-то, что стоит против вашей базы данных! – B4NZ41

+0

любая специальная функция, которую вы любите использовать для дезинфекции? – GK1667

ответ

57

Короткий ответ на ваш вопрос «нет».

В строгом смысле, на уровне базы данных подготовленные операторы позволяют привязывать параметры только к битам «values» инструкции SQL.

Один из способов думать об этом - «вещи, которые могут быть заменены во время исполнения заявления без изменения его значения». Имя (и) таблицы не является одним из этих значений времени выполнения, поскольку оно определяет правильность самого оператора SQL (то есть, какие имена столбцов являются допустимыми) и изменение его во время выполнения потенциально может изменить, является ли оператор SQL действительным.

На немного более высоком уровне, даже в интерфейсах базы данных, которые эмулируют подстановку подготовленного оператора, а не фактически посылают подготовленные операторы в базу данных, такие как PDO, которые могли бы позволить вам использовать местозаполнитель в любом месте (поскольку заменитель места заменяется перед отправкой в ​​базу данных в этих системах) значение заполнителя таблицы будет строкой и вложено как таковое в SQL, отправленное в базу данных, поэтому SELECT * FROM ? с mytable, поскольку параметр фактически завершит отправку SELECT * FROM 'mytable' в базу данных , что является недопустимым SQL.

Лучше всего, чтобы продолжить

SELECT * FROM {$mytable} 

но вы абсолютно должны иметь белый список таблиц, которые проверяют на первый, если это $mytable исходит из пользовательского ввода.

+0

Отличный совет, но по моему опыту это не распространяется на более крупные динамические веб-сайты. Если ваш сайт имеет многопользовательскую настройку, большое и постоянное обновление инвентаря и т. Д., Это решение будет чрезвычайно сложно применить. –

+10

Размер веб-сайта имеет очень мало общего с количеством таблиц и знает, какие конечные пользователи могут направлять запросы через параметры. В конечном счете это странный веб-сайт, который позволяет конечным пользователям сделать это в первую очередь. –

-3

В конце концов, я получаю прекрасный ответ. как написать имя таблицы в инструкции подготовки динамически. все трюки происходят с '{}'. вы должны использовать свою переменную внутри этого '{}'. он работает в моем коде.

$tablename = "run_time_variable";  
$stmt = $conn->prepare("INSERT INTO `{$tablename}` (name, address, phone) VALUES (?,?,?)"); 
$stmt->bind_param("sss", $name, $address, $phone); 
$stmt->execute(); 
+0

Как это ответить на часть «добавить в существующую для защиты от SQL-инъекции»? –

Смежные вопросы