So entkommen Sie einfachen SQL-Abfragen in C # für SqlServer


78

Ich verwende eine API, die eine SQL-Zeichenfolge erwartet. Ich nehme eine Benutzereingabe, entkomme sie und leite sie an die API weiter. Die Benutzereingabe ist recht einfach. Es werden Spaltenwerte abgefragt. Wie so:

string name = userInput.Value;

Dann erstelle ich eine SQL-Abfrage:

string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
                           name.replace("'", "''"));

Ist das sicher genug? Wenn dies nicht der Fall ist, gibt es eine einfache Bibliotheksfunktion, die Spaltenwerte sicher macht:

string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
                           SqlSafeColumnValue(name));

Die API verwendet SQLServer als Datenbank.


Parametrieren Sie es! Eine Google-Suche von SO nach "SQL Injection" Bearbeiten: Als Antwort auf Seva Alekseyev, SO Antwort mit Zeichen 8 Injection
gbn

3
Sie müssen Parameter verwenden.
SLaks

2
@SLaks, Offensichtlich erlaubt die API es nicht. Vielleicht braucht er eine neue API.
C. Ross

3
@sri Sie erhalten bessere Antworten, wenn Sie erklären, warum Sie keine Parameter verwenden können / wollen.
Foole

Gibt es eine Möglichkeit, Abfragen mit Listen zu parametrisieren? SELECT [Name], [Value] FROM [SomeTable] WHERE [Name] IN (@ListOfNames) Ich meine einen anderen Weg als var listParNames = listNames.Select(name => { var pname = string.Format("@n{0}", cmd.Parameters.Count); cmd.Parameters.AddWithValue(pname, name); return pname; }); cmd.CommandText = string.Format("SELECT [Name], [Value] FROM [SomeTable] WHERE [Name] in ({0})", string.Join(",", listParNames.ToArray())); eher direktcmd.Parameters.AddWithValue("@ListOfNames", listNames.ToArray());
Mizuki Nakeshu

Antworten:


137

Da die Verwendung von SqlParameter keine Option ist, ersetzen Sie in den Zeichenfolgenliteralen einfach 'durch' '(das sind zwei einfache Anführungszeichen, nicht ein doppeltes Anführungszeichen). Das ist es.

Für potenzielle Downvoter: Lesen Sie die erste Zeile der Frage erneut. "Parameter verwenden" war auch meine Darmreaktion.

EDIT: Ja, ich weiß über SQL-Injection-Angriffe. Wenn Sie der Meinung sind, dass dieses Zitat für diese anfällig ist, geben Sie bitte ein funktionierendes Gegenbeispiel an. Ich denke es ist nicht.


13
Es ist ein wenig nach Robert. So geht das. Bei korrekter Angabe würde Bobbys unorthodoxer Name vollständig in der Datenbank gespeichert.
Seva Alekseyev

45
Seva Alekseyev, vielen Dank, dass Sie meine Frage gelesen und versucht haben, sie zu beantworten. Vielen Dank, dass Sie mir nicht über "Best Practices" gepredigt haben. Und danke, dass du nicht versucht hast, mich zu "erziehen" Wirklich, danke!
sc45

12
Um es festzuhalten, ich denke immer noch, dass Parameter der richtige Weg sind :) Ich bin jedoch lange genug in diesem Geschäft, um die Existenz von Einschränkungen für Ihre Designs zu verstehen. Kenne ich schon.
Seva Alekseyev

13
@Seva Obwohl jeder weiß, dass der obige Code Injektionen unterliegt, sind Sie manchmal an eine API gebunden, mit der Sie Best Practices einfach nicht befolgen können. Zu oft sorgen sich Programmierer um Dinge, die nicht im Kreis der Anliegen einer bestimmten Aufgabe liegen. Gute Antwort auf die spezifische Frage.
Keith Adler

9
Gute Antwort! Wir brauchen mehr hilfsbereite Menschen wie Sie und weniger Menschen, die bevormunden und aufklären! Ich habe dich hochgestimmt und diesen anderen ahnungslosen Kerl herabgestimmt
Christian

0

Ich habe dynamisches SQL (ich kann hören, wie das Exekutionskommando seine Gewehre lädt) für die Suchfunktion verwendet, aber es wurde immer dann unterbrochen, wenn ein Benutzer nach jemandem mit einem Nachnamen wie "O'Reilly" suchte.

Ich habe es geschafft, eine Problemumgehung zu finden (lesen Sie "Hack"):

Erstellt eine skalarwertige Funktion in SQL, die ein einfaches Anführungszeichen durch zwei einfache Anführungszeichen ersetzt und dem beleidigenden einfachen Anführungszeichen effektiv entgeht, sodass
"... Nachname WIE '% O'Reilly%' UND ..." zu "... Nachname" wird WIE '% O''Reilly%' UND ... "

Diese Funktion wird aus SQL heraus aufgerufen, wenn ich vermute, dass Felder ein einfaches Anführungszeichen enthalten könnten, dh: Vorname, Nachname.

CREATE FUNCTION [dbo].[fnEscapeSingleQuote]
    (@StringToCheck NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @Result NVARCHAR(MAX)
    SELECT @Result = REPLACE(@StringToCheck, CHAR(39), CHAR(39) + CHAR(39))
    RETURN @Result
END

Nicht sehr elegant oder effizient, aber es funktioniert, wenn Sie in einer Notlage sind.


0

Möglicherweise möchten Sie "durch" ersetzen, anstatt zu parametrisieren, wenn Sie das Problem in einer großen Menge von Ad-hoc-SQL in kurzer Zeit mit minimalem Bruchrisiko und minimalen Tests beheben müssen.


0

Verwendung von SqlCommand und Entity Framework exec sp_executesql....

Es gibt also wirklich eine Alternative zu rohen Saiten mit vermutlich Ihrem eigenen Fluchtmuster. Mit SqlCommand verwenden Sie technisch parametrisierte Abfragen, umgehen jedoch die ADO.Net-Abstraktion des zugrunde liegenden SQL-Codes.

Während Ihr Code SQL Injection nicht verhindert, lautet die endgültige Antwort sp_executesql und nicht SqlCommand.

Ich bin mir jedoch sicher, dass es spezielle Handhabungsanforderungen für die Generierung einer SQL Injection-Proof-Zeichenfolge gibt, die sp_executesql verwendet.

Siehe: Wie kann ich Werte von einer dynamischen gespeicherten SQL-Prozedur an das Entity Framework zurückgeben?


-4

Einfach:

const string sql = "SELECT * FROM SOME_TABLE WHERE Name = @name";

und fügen Sie den @nameParameter mit dem Wert hinzu:

cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@name", name);

36
Er muss noch die eigentliche SQL-Anweisung aus dem Befehlsobjekt holen, um sie an die API zu übergeben.
reustmd

Er gibt ausdrücklich an, dass er eine API verwendet, die eine SQL-Zeichenfolge akzeptiert. Er benutzt ADO.Net NICHT.
MHollis

@ MHollis genau; Das ist das erste Problem, das sie beheben müssen. Entschuldigung, aber ohne Parameter ist dies nicht ratsam . Es gibt einen Grund, warum Leute über Parameter schreien.
Marc Gravell

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.