2010-06-28 13 views
23

Ich habe mich gefragt, ob es sowieso möglich war, zurückgegebene Spaltennamen mit vorbereiteten Anweisungen anzugeben.Variablenspaltennamen mit vorbereiteten Anweisungen

Ich benutze MySQL und Java.

Wenn ich versuche es:

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

ich diese Art von Anweisung erhalten (Druck direkt vor der Ausführung).

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

ich aber sehen möchte:

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

Ich weiß, dass ich dies für Tabellennamen nicht tun können, here als diskutiert, aber frage mich, ob es irgendeine Art und Weise war es für die Spalte zu tun Namen.

Wenn nicht, dann muss ich nur versuchen und sicherstellen, dass ich die Eingabe bereinigt, so dass es nicht zu SQL-Injection-Schwachstellen führt.

Antwort

24

Dies deutet auf ein fehlerhaftes DB-Design hin. Der Benutzer sollte die Spaltennamen nicht kennen müssen. Erstellen Sie eine echte DB-Spalte, die diese "Spaltennamen" enthält, und speichern Sie stattdessen die Daten.

Auf keinen Fall, nein, Sie können keine Spaltennamen als PreparedStatement Werte festlegen. Sie können nur Spalte Werte als PreparedStatement Werte

gesetzt Wenn Sie in diese Richtung fortsetzen möchten, müssen Sie die Spaltennamen sanieren und verketten/bauen die SQL-Zeichenfolge selbst. Zitieren Sie die separaten Spaltennamen und verwenden Sie String#replace(), um das gleiche Zitat innerhalb des Spaltennamens zu vermeiden.

+0

Nun, der Benutzer braucht die Spaltennamen nicht wirklich zu kennen, aber die benötigten Spaltennamen werden basierend auf den vom Benutzer übermittelten Formularen abgeleitet. Dies wird jedoch auf der Client-Seite gehandhabt, also wollte ich sehen, ob es einen Weg gibt, um sicherzustellen, dass die Daten sicher sind. Soll ich dann einfach die ganze Menge auf die Serverseite verschieben und dadurch sicherstellen, dass die Spaltendaten nicht verändert werden? – KLee1

+2

Behandeln Sie es stattdessen auf der Serverseite. Machen Sie keine geschäftlichen Dinge auf der Client-Seite. – BalusC

+0

@BalusC: _ "Sie können Spaltennamen nicht als PreparedStatement-Werte festlegen" _ - das ist komplett erfunden. Die Verwendung von Spaltennamen in vorbereiteten Anweisungswertlisten ist natürlich möglich - aber das bedeutet nicht, dass es auf diese Weise verwendet werden sollte, es ist immer noch ein schlechtes Design. – specializt

2

Ich denke, dass dieser Fall nicht funktionieren kann, weil der ganze Punkt der vorbereiteten Anweisung ist, den Benutzer daran zu hindern, uncapsed Query Bits zu setzen - so werden Sie immer den Text zitiert oder maskiert haben.

Sie müssen diese Eingabe in Java bereinigen, wenn Sie die Abfragestruktur sicher beeinflussen möchten.

+0

Sie haben Recht auf die "es nicht funktionieren kann". Der erste Grund für PreparedStatement war jedoch die Ressourceneffizienz, die es ermöglichte, eine Anweisung zwischenzuspeichern und sie mehrfach zu übergeben, indem nur die Werte geändert wurden (besonders für OLTP). Die Widerstandsfähigkeit gegenüber SQL-Injection-Versuchen ist ein sehr wünschenswerter Nebeneffekt. – Insac

12

Bereiten Sie eine Whitelist zulässiger Spaltennamen vor. Verwenden Sie die 'Abfrage', um in der Whitelist nachzusehen, ob der Spaltenname vorhanden ist. Wenn nicht, lehnen Sie die Abfrage ab.

0

Verwenden Sie sql Injektion Nachteil von Statement Interface als Vorteil. Beispiel:

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

Unten ist die Lösung in Java.

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

Ihre Antwort sieht gut aus, aber Sie sollten auch Ihren Code beschreiben –

+5

Diese Antwort führt direkt zu einem SQL-Injection-Angriff. –

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 
} 
Verwandte Themen