Идентификация имен столбцов в операторах PDO

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

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

  • mysql_real_escape_string требует для нас ресурса соединения mysql, чтобы исключить его
  • PDO :: quote добавляет кавычки вокруг имен полей, что делает их бесполезными в запросе
  • добавляет работу, но не очень безопасен

Кто-нибудь имеет представление о том, как лучше всего правильно вставить имена полей в запрос, прежде чем передавать его в PDO :: prepare?

Solutions Collecting From Web of "Идентификация имен столбцов в операторах PDO"

Стандартным способом ANSI для идентификатора с разделителями является:

SELECT "field1" ... 

и если есть «во имя, удвойте его:

 SELECT "some""thing" ... 

К сожалению, это не работает в MySQL с настройками по умолчанию, потому что MySQL предпочитает думать, что двойные кавычки являются альтернативой одинарным кавычкам для строковых литералов. В этом случае вам нужно использовать обратные (как описано Björn) обратные слэши.

Чтобы правильно выполнить обратную косую черту, вам понадобится mysql_real_escape_string, потому что она зависит от набора символов. Но точка спорна, потому что ни mysql_real_escape_string, ни addlashes не избегают символа backquote . Если вы можете быть уверены, что в именах столбцов никогда не будет символов, отличных от ASCII, вы можете избежать просто ручного обратного слэша – экранирования символов `и \.

В любом случае, это несовместимо с другими базами данных. Вы можете сказать MySQL, чтобы разрешить синтаксис ANSI, установив опцию конфигурации ANSI_QUOTES. Аналогичным образом, по умолчанию SQL Server также дросселирует по двойным кавычкам; он использует еще один синтаксис, а именно квадратные скобки. Опять же, вы можете настроить его для поддержки синтаксиса ANSI с опцией «quoted_identifier».

Резюме: если вам нужна только совместимость MySQL:

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

Если вам нужна совместимость между СУБД, выполните следующие действия:

б. используйте двойные кавычки и требуйте, чтобы пользователи MySQL / SQL-Server соответствующим образом изменили конфигурацию. Запретить двойные кавычки в имени (поскольку Oracle не может справиться с ними даже с экранированием). Или,

с. имеют настройку для MySQL vs SQL Server vs Others и создают в зависимости от этого либо синтаксис backquote, square bracket или double-quote. Запретить как двойные кавычки, так и обратную косую черту / backquote / nul.

Это то, на что вы надеетесь, что уровень доступа к данным будет иметь функцию, но PDO этого не делает.

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

Сводная информация о сводке: gnnnnnnnnnnnh.

Правильный ответ:

  str_replace ("` "," `` ", $ fieldname) 

Неправильно:

 mysql> SELECT `col \" umn` FROM user;
 ОШИБКА 1054 (42S22): Неизвестный столбец 'col \ "umn' в 'списке полей'

Правильно:

 mysql> SELECT `kid``s` FROM user;
 ОШИБКА 1054 (42S22): Неизвестная колонка «kid`s» в «списке полей»
 mysql> SELECT `` `column``name``` FROM user;
 ОШИБКА 1054 (42S22): Неизвестный столбец `` column`name` 'в' списке полей '

(Обратите внимание, что в последнем примере имя столбца содержит 3 (три) дополнительных обратных тика в нем, чтобы показать крайний случай)

Это может повлиять на производительность, но оно должно быть безопасным.

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

Если есть совпадение, вы можете использовать предоставленные пользователем данные, не требуя каких-либо экранов.

Если нет совпадений, то это опечатка или взлома – в любом случае это «ошибка» во введенных данных, и запрос не должен запускаться.

То же самое можно было бы сделать для «динамических» имен таблиц, запустив запрос SHOW TABLES и соответствующий результат.

В одном из моих приложений у меня есть сценарий «install»; часть этого запроса запрашивает имена полей базы данных и таблицы, а затем записывает файл php, который всегда ссылается на него, поэтому я не постоянно запускаю запросы DESCRIBE снова в базе данных, например

 $db_allowed_names['tableName1']['id'] = 1; $db_allowed_names['tableName1']['field1'] = 1; $db_allowed_names['tableName1']['field2'] = 1; $db_allowed_names['tableName2']['id'] = 1; $db_allowed_names['tableName2']['field1'] = 1; $db_allowed_names['tableName2']['field2'] = 1; $db_allowed_names['tableName2']['field3'] = 1; if($db_allowed_names['tableName1'][$_POST['field']]) { //ok } 

Я использую такие ключи массива как это, поскольку оператор if немного быстрее, чем поиск in_array

Как насчет чего-то подобного?

 function filter_identifier($str, $extra='') { return preg_replace('/[^a-zA-Z0-9_'.$extra.']/', '', $str); } try { $res = $db->query('SELECT '.filter_identifier($_GET['column'], '\*').' FROM '.filter_identifier($_GET['table']).' WHERE id = ?', $id); } catch (PDOException $e) { die('error querying database'); } 

Это простой список символов на основе белого списка. Любые символы, не входящие в список, будут удалены. К счастью для меня, мне удалось создать базу данных и таблицы, поэтому я знаю, что никогда не будет никаких символов вне «a-zA-Z0-9_» (обратите внимание: нет места). Вы можете добавить дополнительные символы в список через $ extra arg. Если кто-то попытался поставить «(SELECT * FROM users),« в столбце », он будет отфильтровываться до « SELECT * FROMusers » , что вызовет исключение 🙂

Я стараюсь избегать дополнительных запросов, если это вообще возможно (я очень чувствителен к производительности). Так что, например, делать DESCRIBE заранее или жестко кодировать массив таблиц / столбцов для проверки, я бы предпочел не делать.

Уверенный дизайн проекта, но для вашей проблемы: объедините свои имена полей с помощью `и используйте addlashes для имени.

 select `field1`, `field2` from table where `field3`=:value