Я понимаю, что подготовленные заявления – это лучший способ поиска защиты от SQL-инъекции. Однако они обеспечивают покрытие ограниченным образом; например, в тех случаях, когда я позволяю пользователю решать, как должен быть порядок по операции (т. е. это ASC или DESC? и т. д.), я не получаю никакого покрытия там с подготовленными операциями.
Я понимаю, что я могу сопоставить ввод пользователя с предварительно определенным белым списком. Но это возможно только тогда, когда белый список можно создать или догадаться заранее заранее.
Например, в случаях, о которых я упоминал выше (ASC или DESC), это можно легко сопоставить и проверить с помощью списка принятых значений. Но разве не существует ситуации, когда часть оператора SQL не может быть проверена против белого списка?
Если такая ситуация существует, то какой рекомендуемый подход?
Если я должен был избежать user_input, используя встроенную утилиту для запуска базовой базы данных (такую как mysqL_real_escape_string для mysql) по всем направлениям, где я мог бы потерпеть неудачу?
Я задаю этот вопрос с предположения, что я всегда создаю свои SQL-выражения с указанными значениями – даже для целых чисел …
Давайте посмотрим на следующий пример и подумаем об этом.
select {$fields} from {$table} where Age='{$age}' order by {$orderby_pref}
Предположим, что все вары предоставлены пользователем.
Если бы я был в mysql_real_escape_string всеми переменными в вышеприведенном SQL (в отличие от использования подготовленных операторов, которые охватывают меня только на полпути, заставляя меня поднимать белые списки для другой половины, что это не может помочь), не было бы он одинаково безопасным ( и проще кодировать)? Если нет, то в результате чего утилита отключения сценария ввода завершится неудачей?
$fields = mysql_escape($fields); $table = mysql_escape($table); $age = mysql_escape($age); $orderby_pref = mysql_escape($orderby_pref); select {$fields} from {$table} where Age='{$age}' order by {$orderby_pref}
Вам всегда нужно использовать белые списки для таких вещей, как имена таблиц или столбцов , независимо от того, используете ли вы подготовленные инструкции или функции escape-функции mysql
.
Проблема заключается в том, что имена таблиц и имена столбцов не цитируются в одинарных или двойных кавычках, поэтому, если вы используете функцию, которая специально цитирует эти символы (и, конечно, некоторые из них …), она ничего не сделает для имени вашей таблицы.
Рассмотрим имя таблицы my_table; DELETE * FROM mysql; SELECT * FROM my_table
my_table; DELETE * FROM mysql; SELECT * FROM my_table
my_table; DELETE * FROM mysql; SELECT * FROM my_table
. Ничто в этой строке не будет экранировано функциями escape-функции mysql, но это определенно строка, которую вы хотите проверить против белого списка.
Кроме того, функции escape-функций mysql
имеют проблемы с наборами символов, которые могут сделать их бесполезными, поэтому вам всегда лучше подготовленные операторы.
Вы можете использовать PDO, и ваша жизнь станет проще …:
# Order switch(strtoupper($Order)){ default: case 'ASC': $Order = 'ASC'; break; case 'DESC': $Order = 'DESC'; break; } # ID $ID = 39; $Username = 'David'; # Query $Query = $this->DB->Main->prepare('SELECT * FROM Table WHERE ID = :ID AND Username = :Username ORDER BY HellBob '.$Order); $Query->bindValue(':ID', $ID, PDO::PARAM_INT); $Query->bindValue(':Username', $Username, PDO::PARAM_STR); # All good ? if(!$Query->execute()){ exit('Error'); } // Results $Row = $Query->fetch(PDO::FETCH_ASSOC);
Вам не нужно беспокоиться о котировках или SQL-инъекциях. Вы можете использовать простой «белый список», как вы упомянули, чтобы получить переменную в ваш запрос.