2015-10-15 12 views
7

Ho una tabella Project con due colonne - ProjectId e ProjectName - e sto scrivendo una funzione che costruisce ed esegue un SqlCommand per interrogare il database per gli ID di un Progetto con un nome specifico. Questo comando funziona, ma è vulnerabile a SQL Injection:Perché String.Format funziona ma SqlCommand.Parameters.Add non?

string sqlCommand = String.Format("SELECT {0} FROM {1} WHERE {2} = {3}", 
      attributeParam, tableParam, idParam, surroundWithSingleQuotes(idValue)); 

SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection); 
using (SqlDataAdapter adapter = new SqlDataAdapter(command)) 
{ 
    DataTable attributes = new DataTable(); 
    adapter.Fill(attributes); 
    ... 
} 

attributeParam, tableParam, idParam, e idValue sono tutte le stringhe. Ad esempio, potrebbero essere "ProjectId", "Project", "ProjectName" e "MyFirstProject", rispettivamente. surroundWithSingleQuotes circonda una stringa con '', quindi surroundWithSingleQuotes(idValue) == "'MyFirstProject'". Sto cercando di scrivere questa funzione nel modo più generale possibile in quanto potrei voler ottenere tutto un attributo dato da una tabella in futuro.

Anche se quanto sopra String.Format funziona, questo non lo fa:

string sqlCommand = String.Format("SELECT @attributeparam FROM {0} WHERE " + 
    "@idparam = @idvalue", tableParam); 

command.Parameters.Add(new SqlParameter("@attributeparam", attributeParam)); 
command.Parameters.Add(new SqlParameter("@idparam", idParam)); 
command.Parameters.Add(new SqlParameter("@idvalue", 
    surroundWithSingleQuotes(idValue))); 

SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection); 
using (SqlDataAdapter adapter = new SqlDataAdapter(command)) 
{ 
    DataTable attributes = new DataTable(); 
    adapter.Fill(attributes); 
    ... 
} 

io non so perché. Non ricevo alcun messaggio di errore, ma quando riempio il mio DataTable utilizzando un SqlDataAdapter, il DataTable non contiene nulla. Qui ci sono diversi approcci che ho preso, senza alcun risultato:

  • seguito this answer e Microsoft's documentation, utilizzando AddWithValue o utilizzando Parameters.Add e SqlParameter.Value.
  • Sostituire in modo selettivo {0}, {1}, {2} e {3} in String.Format con il valore effettivo o la stringa di parametro.

In altri punti del mio codice, ho utilizzato le query parametrizzate (anche se con un solo parametro) senza problemi.

+2

Gli unici parametri del pezzo possono essere sostituiti direttamente '{3}'. –

+2

Non è possibile utilizzare un parametro per il nome di una colonna. Dovrai comunque usare 'string.Format' per questo, proprio come per il nome della tabella. – juharr

risposta

7

Fondamentalmente i parametri in SQL funzionano solo con valori - non identificatori di colonne o tabelle. Nell'esempio, solo il parametro finale rappresenta un valore.

Se è necessario essere dinamici in termini di nomi di colonne e tabelle, è necessario creare da sé quella parte di SQL. Fare molta attenzione per tutti i normali motivi associati agli attacchi di SQL injection. Idealmente, consente solo una lista bianca nota di valori di tabella e colonna. Se devi essere più generale, ti suggerisco di eseguire validazioni molto restrittive e quote the identifiers per evitare conflitti con le parole chiave (o vietarle interamente, idealmente).

Continuare a utilizzare i parametri SQL per i valori, ovviamente.

+0

Estremamente utile - grazie mille! – rln

0

Questa è una dichiarazione valida: SELECT * FROM SomeTable WHERE [email protected]

considerando che tale non è: SELECT * FROM @param

Questo significa che è possibile utilizzare i parametri per i valori e non per i nomi di tabella, nomi di vista, i nomi delle colonne ecc

Problemi correlati