2010-06-28 28 views
23

Me preguntaba si había alguna forma de especificar los nombres de las columnas devueltas usando declaraciones preparadas.Nombres de columnas variables usando declaraciones preparadas

Estoy usando MySQL y Java.

Cuando lo intento:

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"); 

consigo este tipo de declaración (impresión justo antes de la ejecución).

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

Me gustaría ver al menos:

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

Yo sé que no puedo hacer esto para nombres de tabla, como se discutió here, pero se preguntaba si había alguna manera de hacerlo para la columna nombres.

Si no lo hay, entonces solo tendré que intentar asegurarme de que saneo la entrada para que no dé lugar a vulnerabilidades de inyección de SQL.

Respuesta

24

Esto indica un mal diseño de la base de datos. El usuario no debería necesitar conocer los nombres de las columnas. Cree una columna DB real que contenga esos "nombres de columna" y almacene los datos a lo largo de ella.

En cualquier caso, no, no puede establecer los nombres de las columnas como PreparedStatement. Sólo se puede establecer la columna valores comoPreparedStatement valores

Si desea continuar en esta dirección, es necesario desinfectar los nombres de columna y concatenar/construir la cadena SQL sí mismo. Cite los nombres de las columnas por separado y use String#replace() para evitar la misma cita dentro del nombre de la columna.

+0

Bueno, el usuario no necesita saber los nombres de las columnas, pero los nombres de las columnas necesarias se deducen en función de los formularios enviados por el usuario. Sin embargo, esto se maneja desde el lado del cliente, así que quería ver si había alguna forma de garantizar que los datos estuvieran seguros. ¿Debería entonces mover todo el lote al lado del servidor, asegurando así que los datos de la columna no estén contaminados? – KLee1

+2

En cambio, tráelo en el lado del servidor. No hagas negocios en el lado del cliente. – BalusC

+0

@BalusC: _ "no puede establecer nombres de columnas como valores PreparedStatement" _ - eso está completamente inventado. El uso de nombres de columna dentro de las listas de valores de las declaraciones preparadas es, por supuesto, posible, pero eso no significa que deba usarse de esa manera, todavía es un mal diseño. – specializt

2

Creo que este caso no puede funcionar porque el objetivo de la declaración preparada es evitar que el usuario ingrese bits de consulta no escaneados, por lo que siempre tendrá el texto cotizado o escapado.

Deberá desinfectar esta entrada en Java si desea afectar la estructura de la consulta de forma segura.

+0

Tienes razón en el "no se puede trabajar". Sin embargo, la primera razón para PreparedStatement se debió a la eficiencia de los recursos, lo que permite mantener una declaración en caché y enviarla varias veces simplemente cambiando los valores (especialmente para OLTP). Su resistencia a los intentos de inyección de SQL es un efecto secundario muy deseable. – Insac

12

Prepare una lista blanca de nombres de columna permitidos. Use la 'consulta' para buscar en la lista blanca para ver si el nombre de la columna está allí. Si no, rechace la consulta.

0

Utilice la desventaja de inyección sql de Statement Interface como ventaja. Ej:

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

A continuación se muestra la solución en java.

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

Su respuesta es correcta, pero también debe describir su código –

+5

Esta respuesta conduce directamente a un ataque de inyección 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 
} 
Cuestiones relacionadas