Имена столбцов переменных с использованием подготовленных операторов

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

Я использую MySQL и Java.

Когда я пробую это:

String columnNames="d,e,f"; //Actually from the user...
String name = "some_table"; //From user...
String query = "SELECT a,b,c,? FROM " + name + " WHERE d=?";//...
stmt = conn.prepareStatement(query);
stmt.setString(1, columnNames);
stmt.setString(2, "x");

Я получаю этот тип оператора (печать прямо перед выполнением).

SELECT a,b,c,'d,e,f' FROM some_table WHERE d='x'

Однако хотелось бы увидеть:

SELECT a,b,c,d,e,f FROM some_table WHERE d='x'

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

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


person KLee1    schedule 28.06.2010    source источник


Ответы (7)


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

И в любом случае, нет, вы не можете установить имена столбцов как значения PreparedStatement. Вы можете установить только значения столбца как PreparedStatement значений.

Если вы хотите продолжить в этом направлении, вам нужно очистить имена столбцов (чтобы избежать SQL Injection) и соедините/создайте строку SQL самостоятельно. Заключите в кавычки имена отдельных столбцов и используйте String#replace(), чтобы избежать той же кавычки внутри имени столбца.

person BalusC    schedule 28.06.2010
comment
Ну, на самом деле пользователю не нужно знать имена столбцов, но необходимые имена столбцов выводятся на основе форм, отправленных пользователем. Однако это обрабатывается на стороне клиента, поэтому я хотел посмотреть, есть ли способ обеспечить безопасность данных. Должен ли я тогда просто переместить всю партию на сервер, тем самым гарантируя, что данные столбца не будут испорчены? - person KLee1; 29.06.2010
comment
Вместо этого обработайте это на стороне сервера. Не делайте деловые вещи на стороне клиента. - person BalusC; 29.06.2010
comment
@BalusC: вы не можете устанавливать имена столбцов в качестве значений PreparedStatement - это полностью выдумано. Использование имен столбцов внутри подготовленных списков значений операторов, конечно, возможно, но это не означает, что их следует использовать таким образом, это по-прежнему плохой дизайн. - person specializt; 23.05.2015
comment
Я бы хотел, чтобы вы динамически ограничивали поля для данного ресурса, используя REST с JSON. Не все хотят, чтобы возвращался весь ресурс, и не все хотят создавать 1000 запросов для каждой перестановки указанных столбцов. - person npn_or_pnp; 24.03.2016
comment
Как насчет динамического упорядочения запроса с использованием переменного имени столбца? Будет ли это считаться плохим дизайном? - person sero; 26.10.2017

Подготовьте белый список разрешенных имен столбцов. Используйте «запрос», чтобы найти в белом списке имя столбца. Если нет, отклоните запрос.

person wgl    schedule 26.04.2012

Принятый ответ на самом деле неверен. Хотя подход OP указывал на плохой дизайн БД, он может потребоваться бизнес-логике (например, MySQL IDE).

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

Что-то вроде этого будет работать:

SELECT ??, ??, ?? FROM ?? WHERE ?? < ? 

Установите значения ['id', 'name', 'address', 'user', 'id', 100]

person DraganescuValentin    schedule 05.01.2020
comment
Это очень интересный комментарий. Я не смог найти никакой ссылки на синтаксис этого экранированного значения параметра (??). Не могли бы вы указать мне на один? - person where_; 09.03.2020
comment
Я не помню, где я это видел, точно не в официальных документах. Тем не менее, я успешно использую это в игрушечном проекте. - person DraganescuValentin; 12.03.2020

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

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

person G__    schedule 28.06.2010
comment
Вы правы в том, что это не может работать. Однако первая причина для PreparedStatement заключалась в эффективности использования ресурсов, что позволяло хранить оператор в кэше и отправлять его несколько раз, просто изменяя значения (отлично особенно для OLTP). Его устойчивость к попыткам SQL-инъекций является очень желательным побочным эффектом. - person Insac; 20.12.2016

Используйте недостаток инъекций sql в интерфейсе операторов в качестве преимущества. Бывший:

st=conn.createStatement();
String columnName="name";
rs=st.executeQuery("select "+ columnName+" from ad_org ");
person Syed Abdul Khaliq    schedule 03.02.2017

Ниже приведено решение в java.

String strSelectString = String.format("select %s, %s from %s", strFieldName, strFieldName2, strTableName);
person Grbh Niti    schedule 19.04.2017
comment
Ваш ответ выглядит нормально, но вы также должны описать свой код. - person Anil Agrawal; 19.04.2017
comment
Этот ответ ведет непосредственно к атаке с использованием SQL-инъекций. - person Clement Cherlin; 23.05.2017
comment
Да, это пример уязвимого кода, как описано здесь: find-sec-bugs.github.io/bugs.htm#SQL_INJECTION_JPA - person Guillaume Husta; 15.06.2018

person    schedule
comment
Вопрос касается использования подготовленного статемента(). Ваше решение не использует его. Он подвержен SQL-инъекциям. - person nanosoft; 10.05.2019
comment
Ой! Генерация кода SQL путем объединения строк без экранирования! Пожалуйста, удалите это, прежде чем ваш босс узнает, что вы это написали. - person ceving; 25.08.2020