2010-06-28 4 views
23

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

Я использую 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' 

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

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

ответ

24

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

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

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

+0

Ну, пользователю действительно не нужно знать имена столбцов, но требуемые имена столбцов выводятся на основе форм, представленных пользователем. Это обрабатывается на стороне клиента, хотя, поэтому я хотел посмотреть, есть ли способ обеспечить безопасность данных. Должен ли я просто переместить всю партию на серверную сторону, тем самым, чтобы данные столбца не были заполнены? – KLee1

+2

Вместо этого обрабатывайте его на стороне сервера. Не делайте деловые дела на стороне клиента. – BalusC

+0

@BalusC: _ "вы не можете установить имена столбцов в качестве значений PreparedStatement" _ - это полностью составлено. Разумеется, использование имен столбцов внутри готовых таблиц значений инструкций возможно, но это не значит, что его следует использовать таким образом, он все еще плохой дизайн. – specializt

2

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

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

+0

Вы правы на "он не может работать". Однако первая причина для PreparedStatement заключалась в ресурсоэффективности, позволяющей хранить оператор в кэше и передавать его несколько раз, просто изменяя значения (особенно для OLTP). Его устойчивость к попыткам SQL Injection является очень хорошим побочным эффектом. – Insac

12

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

0

Использовать недостаток использования sql интерфейса Statement как преимущество. Ex:

st=conn.createStatement(); 
String columnName="name"; 
rs=st.executeQuery("select "+ columnName+" from ad_org "); 
1

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

String strSelectString = String.format("select %s, %s from %s", strFieldName, strFieldName2, strTableName); 
+0

Ваш ответ выглядит нормально, но вы также должны описать свой код –

+5

. Этот ответ ведет непосредственно к атаке SQL-инъекции. –

0
public void MethodName(String strFieldName1, String strFieldName2, String strTableName) 
{ 
//Code to connect with database 
String strSQLQuery=String.format("select %s, %s from %s", strFieldName, strFieldName2, strTableName); 
st=conn.createStatement(); 
rs=st.executeQuery(strSQLQuery); 
//rest code 
}