Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Parametrisieren Sie eine SQL IN-Klausel

Sie können jeden parametrisieren Wert, also so etwas wie:

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]);
    }
}

Was Ihnen Folgendes geben wird:

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"

Nein, dies ist nicht offen für SQL-Injection. Der einzige in CommandText eingefügte Text basiert nicht auf Benutzereingaben. Es basiert ausschließlich auf dem hartcodierten Präfix „@tag“ und dem Index eines Arrays. Der Index wird immer eine Ganzzahl sein, wird nicht vom Benutzer generiert und ist sicher.

Die vom Benutzer eingegebenen Werte werden immer noch in Parameter gefüllt, sodass dort keine Schwachstelle besteht.

Bearbeiten:

Abgesehen von Bedenken hinsichtlich der Injektion sollten Sie beachten, dass die Konstruktion des Befehlstexts zur Aufnahme einer variablen Anzahl von Parametern (wie oben) die Fähigkeit des SQL-Servers behindert, zwischengespeicherte Abfragen zu nutzen. Das Endergebnis ist, dass Sie mit ziemlicher Sicherheit den Wert der Verwendung von Parametern überhaupt verlieren (im Gegensatz zum bloßen Einfügen der Prädikat-Strings in die SQL selbst).

Nicht, dass zwischengespeicherte Abfragepläne nicht wertvoll wären, aber meiner Meinung nach ist diese Abfrage nicht annähernd kompliziert genug, um einen großen Nutzen daraus zu ziehen. Während die Kompilierungskosten die Ausführungskosten erreichen (oder sogar übersteigen) können, sprechen Sie immer noch von Millisekunden.

Wenn Sie über genügend RAM verfügen, würde SQL Server wahrscheinlich auch einen Plan für die allgemeine Anzahl von Parametern zwischenspeichern. Ich nehme an, Sie könnten immer fünf Parameter hinzufügen und die nicht angegebenen Tags NULL sein lassen - der Abfrageplan sollte derselbe sein, aber es scheint mir ziemlich hässlich und ich bin mir nicht sicher, ob es die Mikrooptimierung wert wäre (obwohl, auf Stack Overflow – es kann sich durchaus lohnen).

Außerdem parametrisieren SQL Server 7 und höher Abfragen automatisch, sodass die Verwendung von Parametern aus Leistungssicht nicht unbedingt erforderlich ist – sie ist jedoch kritisch aus Sicherheitsgründen - insbesondere bei solchen vom Benutzer eingegebenen Daten.