2010-06-28 5 views
23

Je me demandais s'il était possible de spécifier des noms de colonne renvoyés en utilisant des instructions préparées. J'utilise MySQL et Java.Noms de colonnes variables utilisant des instructions préparées

Quand je l'essayer:

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

Je reçois ce type de déclaration (impression juste avant l'exécution).

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

Je voudrais voir cependant:

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

Je sais que je ne peux pas le faire pour les noms de table, comme discuté here, mais je me demandais s'il y avait un moyen de le faire pour la colonne des noms.

Si ce n'est pas le cas, alors je vais devoir essayer de m'assurer que je désinfecte l'entrée afin qu'elle n'aboutisse pas à des vulnérabilités d'injection SQL.

Répondre

24

Cela indique une mauvaise conception de base de données. L'utilisateur ne devrait pas avoir besoin de connaître les noms des colonnes. Créez une colonne DB réelle qui contient ces "noms de colonne" et stockez les données à la place.

De toute façon, non, vous ne pouvez pas définir les noms de colonne comme valeurs PreparedStatement. Vous ne pouvez définir la colonne valeurs comme PreparedStatement valeurs

Si vous souhaitez continuer dans cette direction, vous devez aseptiser les noms de colonnes et concaténer/construire la chaîne SQL vous-même. Citer les noms de colonne séparés et utiliser String#replace() pour échapper la même citation dans le nom de la colonne.

+0

Eh bien, l'utilisateur n'a pas réellement besoin de connaître les noms des colonnes, mais les noms de colonnes nécessaires sont déduits en fonction des formulaires soumis par l'utilisateur. Cela est géré du côté client, donc je voulais voir s'il y avait un moyen de garantir la sécurité des données. Devrais-je simplement déplacer tout le lot vers le serveur, pour que les données de la colonne ne soient pas endommagées? – KLee1

+2

Manipulez-le du côté serveur à la place. Ne faites pas les affaires du côté client. – BalusC

+0

@BalusC: _ "vous ne pouvez pas définir les noms de colonnes comme des valeurs PreparedStatement" _ - elles sont entièrement composées. L'utilisation de noms de colonne à l'intérieur de listes de valeurs d'instructions préparées est bien sûr possible - mais cela ne signifie pas qu'il devrait être utilisé de cette façon, il s'agit toujours d'un mauvais design. – specializt

2

Je pense que ce cas ne peut pas fonctionner car tout le point de l'instruction préparée est d'empêcher l'utilisateur de placer des bits de requête non échappés - de sorte que le texte sera toujours cité ou échappé.

Vous aurez besoin de désinfecter cette entrée dans Java si vous souhaitez affecter la structure de la requête en toute sécurité.

+0

Vous avez raison sur le "il ne peut pas fonctionner". Cependant, la première raison de PreparedStatement était en raison de l'efficacité des ressources, permettant de conserver une instruction mise en cache et de la soumettre plusieurs fois simplement en changeant les valeurs (particulièrement pour OLTP). Sa résilience aux tentatives d'injection SQL est un effet secondaire très souhaitable. – Insac

12

Préparez une liste blanche des noms de colonnes autorisés. Utilisez la 'requête' pour chercher dans la liste blanche pour voir si le nom de la colonne est là. Si ce n'est pas le cas, rejetez la requête.

0

Utiliser l'inconvénient de l'injection sql de l'interface Statement comme avantage. Ex:

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

Voici la solution de java.

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

Votre réponse semble correcte, mais vous devez également décrire votre code. –

+5

Cette réponse mène directement à une attaque par injection 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 
} 
Questions connexes