Параметризованные столбцы SQL?

У меня есть код, который использует параметризованные запросы для предотвращения внедрения, но мне также нужно иметь возможность динамически строить запрос независимо от структуры таблицы. Каков правильный способ сделать это?

Вот пример, скажем, у меня есть таблица со столбцами Имя, Адрес, Телефон. У меня есть веб-страница, на которой я запускаю Показать столбцы и заполняю их раскрывающимся списком в качестве параметров.

Далее у меня есть текстовое поле под названием Search. Это текстовое поле используется в качестве параметра.

В настоящее время мой код выглядит примерно так:

result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);

Я получаю неприглядное чувство от этого все же. Причина, по которой я использую параметризованные запросы, заключается в том, чтобы избежать использования escape. Кроме того, экранирование, скорее всего, не предназначено для экранирования имен столбцов.

Как я могу убедиться, что это работает так, как я задумал?

Редактировать: Причина, по которой мне требуются динамические запросы, заключается в том, что схема настраивается пользователем, и мне не нужно будет исправлять что-либо жестко запрограммированное.


person Martin    schedule 19.09.2008    source источник


Ответы (6)


Вместо того, чтобы передавать имена столбцов, просто передайте идентификатор, который вы кодируете для преобразования в имя столбца с использованием жестко запрограммированной таблицы. Это означает, что вам не нужно беспокоиться о передаче вредоносных данных, поскольку все данные либо переведены на законных основаниях, либо заведомо недействительны. Псевдо-код:

@columns = qw/Name Address Telephone/;
if ($columns[$param]) {
  $query = "select * from contacts where $columns[$param] = ?";
} else {
  die "Invalid column!";
}

run_sql($query, $search);
person zigdon    schedule 19.09.2008
comment
Жесткое кодирование для меня не вариант, спасибо за предложение! - person Martin; 20.09.2008
comment
Моя точка зрения заключается не в жестком кодировании имен столбцов, а в том, чтобы не передавать их из интерфейса. Вы можете получить список столбцов динамически и по-прежнему использовать то же решение, что и выше. Просто не делайте имена столбцов частью передаваемых данных — это защитит вас от любых SQL-инъекций. - person zigdon; 20.09.2008
comment
+1 Да, я люблю говорить: позвольте пользователям вводить данные, но не позволяйте пользователям вводить код. - person Bill Karwin; 25.06.2010

Хитрость заключается в том, чтобы быть уверенным в своих процедурах побега и проверки. Я использую собственную escape-функцию SQL, которая перегружена для литералов разных типов. Я нигде не вставляю выражения (в отличие от литеральных значений в кавычках) непосредственно из пользовательского ввода.

Тем не менее, это можно сделать, я рекомендую отдельную — и строгую — функцию для проверки имени столбца. Разрешите ему принимать только один идентификатор, например

/^\w[\w\d_]*$/

Вам придется полагаться на предположения, которые вы можете сделать о своих собственных именах столбцов.

person harpo    schedule 19.09.2008

Я использую ADO.NET и использование команд SQL и SQLParameters для тех команд, которые решают проблему Escape. Поэтому, если вы также находитесь в среде инструментов Microsoft, я могу сказать, что я очень успешно использую это для создания динамического SQL и при этом защищаю свои параметры.

удачи

person Brad Osterloo    schedule 19.09.2008

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

person Turnkey    schedule 19.09.2008

В стандартном SQL идентификаторы с разделителями заключаются в двойные кавычки. Это означает, что:

SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?

выберет из таблицы SomeTable с указанными заглавными буквами (не версия имени с преобразованием регистра) и применит условие к столбцу SomeColumn с указанными заглавными буквами.

Само по себе это не очень полезно, но... если вы можете применить технику escape() с двойными кавычками к именам, введенным через вашу веб-форму, то вы сможете построить свой запрос достаточно уверенно.

Конечно, вы сказали, что хотите избежать использования escape-последовательности, и вам действительно не нужно использовать ее в параметрах, где вы предоставляете ? заполнители. Но там, где вы вводите в запрос предоставленные пользователем данные, вам необходимо защитить себя от злоумышленников.

Различные СУБД имеют разные способы предоставления идентификаторов с разделителями. MS SQL Server, например, использует квадратные скобки [SomeTable] вместо двойных кавычек.

person Jonathan Leffler    schedule 19.09.2008

Имена столбцов в некоторых базах данных могут содержать пробелы, что означает, что вам придется заключать имя столбца в кавычки, но если ваша база данных не содержит таких столбцов, просто запустите имя столбца через регулярное выражение или какую-либо проверку перед объединением в SQL:

if ( $column !~ /^\w+$/ ) {
  die "Bad column name [$column]";
}
person runrig    schedule 19.09.2008