Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Parametrizzare una clausola SQL IN

Puoi parametrizzare ciascuno valore, quindi qualcosa come:

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
string cmdText = "SELECT * FROM Tags WHERE Name IN ({0})";

string[] paramNames = tags.Select(
    (s, i) => "@tag" + i.ToString()
).ToArray();

string inClause = string.Join(", ", paramNames);
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
    for(int i = 0; i < paramNames.Length; i++) {
       cmd.Parameters.AddWithValue(paramNames[i], tags[i]);
    }
}

Che ti darà:

cmd.CommandText = "SELECT * FROM Tags WHERE Name IN (@tag0, @tag1, @tag2, @tag3)"
cmd.Parameters["@tag0"] = "ruby"
cmd.Parameters["@tag1"] = "rails"
cmd.Parameters["@tag2"] = "scruffy"
cmd.Parameters["@tag3"] = "rubyonrails"

No, questo non è aperto a SQL injection. L'unico testo inserito in CommandText non è basato sull'input dell'utente. Si basa esclusivamente sul prefisso "@tag" hardcoded e sull'indice di un array. L'indice sarà sempre essere un numero intero, non è generato dall'utente ed è sicuro.

I valori immessi dall'utente sono ancora inseriti nei parametri, quindi non c'è alcuna vulnerabilità lì.

Modifica:

A parte i problemi di iniezione, fai attenzione a notare che la costruzione del testo del comando per contenere un numero variabile di parametri (come sopra) impedisce la capacità del server SQL di sfruttare le query memorizzate nella cache. Il risultato netto è che quasi sicuramente perdi il valore dell'utilizzo dei parametri in primo luogo (invece di inserire semplicemente le stringhe di predicato nell'SQL stesso).

Non che i piani di query memorizzati nella cache non siano preziosi, ma IMO questa query non è abbastanza complicata da vederne molti vantaggi. Sebbene i costi di compilazione possano avvicinarsi (o addirittura superare) i costi di esecuzione, stai comunque parlando di millisecondi.

Se hai abbastanza RAM, mi aspetto che SQL Server probabilmente memorizzerebbe nella cache anche un piano per i conteggi comuni dei parametri. Suppongo che tu possa sempre aggiungere cinque parametri e lasciare che i tag non specificati siano NULL:il piano di query dovrebbe essere lo stesso, ma mi sembra piuttosto brutto e non sono sicuro che varrebbe la micro-ottimizzazione (sebbene, su Stack Overflow:potrebbe valerne la pena).

Inoltre, SQL Server 7 e versioni successive parametrizzeranno automaticamente le query, quindi l'utilizzo dei parametri non è realmente necessario dal punto di vista delle prestazioni, tuttavia è critico dal punto di vista della sicurezza, specialmente con dati immessi dall'utente come questo.