Параметризованные столбцы SQL?
-
01-07-2019 - |
Вопрос
У меня есть некоторый код, который использует параметризованные запросы для предотвращения внедрения, но мне также нужно иметь возможность динамически создавать запрос независимо от структуры таблицы.Как правильно это сделать?
Вот пример, допустим, у меня есть таблица со столбцами Name, Address, Phone.У меня есть веб-страница, на которой я запускаю Показывать столбцы и заполните раскрывающийся список "Выбрать" ими в качестве параметров.
Далее, у меня есть текстовое поле под названием Поиск.Это текстовое поле используется в качестве параметра.
В настоящее время мой код выглядит примерно так:
result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);
Хотя у меня от этого возникает неприятное ощущение.Причина, по которой я использую параметризованные запросы, заключается в том, чтобы избежать использования побег.Также, побег скорее всего, он не предназначен для экранирования имен столбцов.
Как я могу убедиться, что это работает так, как я задумал?
Редактировать: Причина, по которой мне требуются динамические запросы, заключается в том, что схема настраивается пользователем, и меня не будет рядом, чтобы исправить что-либо жестко запрограммированное.
Решение
Вместо передачи имен столбцов просто передайте идентификатор, который ваш код преобразует в имя столбца, используя жестко заданную таблицу.Это означает, что вам не нужно беспокоиться о передаче вредоносных данных, поскольку все данные либо переведены легально, либо заведомо недействительны.Псевдошный код:
@columns = qw/Name Address Telephone/;
if ($columns[$param]) {
$query = "select * from contacts where $columns[$param] = ?";
} else {
die "Invalid column!";
}
run_sql($query, $search);
Другие советы
Хитрость заключается в том, чтобы быть уверенным в своих процедурах экранирования и проверки.Я использую свою собственную функцию SQL escape, которая перегружена для литералов разных типов.Нигде я не вставляю выражения (в отличие от литеральных значений в кавычках) непосредственно из пользовательского ввода.
Тем не менее, это можно сделать, я рекомендую отдельную - и строгую — функцию для проверки имени столбца.Разрешите ему принимать только один идентификатор, что-то вроде
/^\w[\w\d_]*$/
Вам придется полагаться на предположения, которые вы можете сделать относительно имен ваших собственных столбцов.
Я использую ADO.NET и использование команд SQL и SqlParameters для тех команд, которые решают проблему Escape.Так что, если вы тоже работаете в среде инструментов Microsoft, я могу сказать, что я очень успешно использую это для создания динамического SQL и при этом защищаю свои параметры
желаю удачи
Создайте столбец на основе результатов другого запроса к таблице, в которой перечислены возможные значения схемы.В этом втором запросе вы можете жестко привязать select к имени столбца, которое используется для определения схемы.если ни одна строка не возвращается, то введенный столбец является недопустимым.
В стандартном SQL идентификаторы с разделителями заключаются в двойные кавычки.Это означает , что:
SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?
выберет из таблицы с именем SomeTable с показанной заглавной буквой (не преобразованную в регистр версию имени) и применит условие к столбцу с именем SomeColumn с показанной заглавной буквой.
Само по себе это не очень полезно, но ... если вы сможете применить метод escape() с двойными кавычками к именам, введенным через вашу веб-форму, тогда вы сможете достаточно уверенно сформировать свой запрос.
Конечно, вы сказали, что хотите избежать использования escape - и действительно, вам не обязательно использовать его для параметров, в которых вы указываете?заполнители.Но там, где вы вводите данные, предоставленные пользователем, в запрос, вам необходимо защитить себя от злоумышленников.
Разные СУБД имеют разные способы предоставления идентификаторов с разделителями.MS SQL Server, например, похоже, использует квадратные скобки [SomeTable] вместо двойных кавычек.
Имена столбцов в некоторых базах данных могут содержать пробелы, что означает, что вам придется заключать имя столбца в кавычки, но если ваша база данных не содержит таких столбцов, просто запустите имя столбца с помощью регулярного выражения или какой-либо проверки перед объединением в SQL:
if ( $column !~ /^\w+$/ ) {
die "Bad column name [$column]";
}