Reichen Parameter wirklich aus, um SQL-Injektionen zu verhindern?

83

Ich habe sowohl meinen Kollegen als auch hier auf SO über die Vorteile der Verwendung von Parametern in SQL-Abfragen, insbesondere in .NET-Anwendungen, gepredigt. Ich bin sogar so weit gegangen, ihnen zu versprechen, Immunität gegen SQL-Injection-Angriffe zu gewähren.

Aber ich frage mich, ob das wirklich stimmt. Gibt es bekannte SQL-Injection-Angriffe, die für eine parametrisierte Abfrage erfolgreich sind? Können Sie zum Beispiel eine Zeichenfolge senden, die einen Pufferüberlauf auf dem Server verursacht?

Es müssen natürlich noch andere Überlegungen angestellt werden, um sicherzustellen, dass eine Webanwendung sicher ist (z. B. das Bereinigen von Benutzereingaben und all diesen Dingen), aber jetzt denke ich an SQL-Injektionen. Ich bin besonders an Angriffen gegen MsSQL 2005 und 2008 interessiert, da dies meine primären Datenbanken sind, aber alle Datenbanken sind interessant.

Bearbeiten: Um zu verdeutlichen, was ich unter Parametern und parametrisierten Abfragen verstehe. Mit Parametern meine ich die Verwendung von "Variablen", anstatt die SQL-Abfrage in einer Zeichenfolge zu erstellen.
Also anstatt dies zu tun:

SELECT * FROM Table WHERE Name = 'a name'

Wir machen das:

SELECT * FROM Table WHERE Name = @Name

und legen Sie dann den Wert des Parameters @Name für das Abfrage- / Befehlsobjekt fest.

Rune Grimstad
quelle
wir sollten klären, was unter Parametern zu verstehen ist (wie Jonathan Leffler betonte) - ich dachte an Parameter für gespeicherte Prozeduren, aber es gibt auch? Parms und {0} Parms ...
Steven A. Lowe
Es ist viel einfacher zu sagen, wir verwenden keine Verkettung, um eine Abfrage zu erstellen.
Da das Tag asp.net ist, gehe ich davon aus, dass Sie Webanwendungen erstellen. In diesem Fall sollten Sie sich auch um XSS-Angriffe und möglicherweise um andere
kümmern

Antworten:

50

Platzhalter reichen aus, um Injektionen zu verhindern. Möglicherweise sind Sie immer noch offen für Pufferüberläufe, aber das ist eine völlig andere Angriffsart als eine SQL-Injection (der Angriffsvektor wäre keine SQL-Syntax, sondern eine Binärdatei). Da die übergebenen Parameter alle ordnungsgemäß maskiert werden, kann ein Angreifer keine Daten übergeben, die wie "Live" -SQL behandelt werden.

Sie können keine Funktionen in Platzhaltern verwenden, und Sie können keine Platzhalter als Spalten- oder Tabellennamen verwenden, da diese maskiert und als Zeichenfolgenliterale in Anführungszeichen gesetzt werden.

Wenn Sie jedoch Parameter als Teil einer Zeichenfolgenverkettung in Ihrer dynamischen Abfrage verwenden, sind Sie weiterhin anfällig für Injektionen, da Ihre Zeichenfolgen nicht maskiert, sondern wörtlich sind. Die Verwendung anderer Typen für Parameter (z. B. Ganzzahl) ist sicher.

Das heißt, wenn Sie die Verwendung von input verwenden, um den Wert von etwas wie security_levelfestzulegen, kann sich jemand einfach selbst zum Administrator in Ihrem System machen und einen Free-for-All haben. Dies ist jedoch nur eine grundlegende Eingabevalidierung und hat nichts mit SQL-Injection zu tun.

Adam Bellaire
quelle
Der entscheidende Punkt ist das Verständnis des Problems, das durch die Antwort von Steve Lowe aufgeworfen wurde, auf die auch in dem Artikel hingewiesen wird, den @mikekidder zitiert - Sie müssen vorsichtig sein, wo immer sich Dynamic SQL befindet, ob in der Anwendung oder auf dem Server. Dynamisches SQL ist gefährlich - kann aber sicher gemacht werden.
Jonathan Leffler
"Es gibt keine Möglichkeit für einen Angreifer, Daten zu übergeben, die wie 'Live' SQL behandelt werden." - Dies ist nicht ganz richtig, siehe Beispiele unten.
Booji Boy
Alle folgenden Beispiele definieren "parametrisierte Abfrage" als SQL-Code, der Parameter akzeptiert. Die normale Definition ist eine Abfrage, die Ihre DBMS-Parametersammlung verwendet. Abgesehen von einem DBMS-Fehler verhindert diese letztere Technik die SQL-Injection.
HTTP 410
2
Ich habe jeden einzelnen Link gelesen. Bitte zitieren Sie alle Links, die auf einen funktionierenden Injektionsangriff auf die DBMS-Parametersammlung verweisen. In der Tat bezieht sich der von Ihnen veröffentlichte Link speziell auf diesen Ansatz, um die SQL-Injection zu verhindern (siehe Abschnitt "Verwenden typsicherer SQL-Parameter").
HTTP 410
Hallo! Könnten Sie einen Link zur Oracle SQL-Grammatik oder Ähnlichem bereitstellen, um diese Antwort zu beweisen? Ich verstehe es und stimme Ihnen absolut zu, aber es wäre großartig, einen offiziellen Link zu Dokumentation, Grammatik usw. zu haben. BestRegards, Raimbek
Raimbek Rakhimbek
13

Nein, es besteht immer noch das Risiko einer SQL-Injection, wenn Sie nicht validierte Daten in eine SQL-Abfrage interpolieren.

Abfrageparameter helfen, dieses Risiko zu vermeiden, indem Literalwerte von der SQL-Syntax getrennt werden.

'SELECT * FROM mytable WHERE colname = ?'

Das ist in Ordnung, aber es gibt andere Zwecke, Daten in eine dynamische SQL-Abfrage zu interpolieren, die keine Abfrageparameter verwenden kann, da es sich nicht um einen SQL-Wert handelt, sondern um einen Tabellennamen, einen Spaltennamen, einen Ausdruck oder eine andere Syntax.

'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
' ORDER BY ' + @colname'

Es spielt keine Rolle, ob Sie gespeicherte Prozeduren verwenden oder dynamische SQL-Abfragen direkt aus dem Anwendungscode ausführen. Das Risiko ist immer noch da.

In diesen Fällen besteht die Abhilfe darin, FIEO nach Bedarf einzusetzen :

  • Filtereingabe: Überprüfen Sie, ob die Daten wie legitime Ganzzahlen, Tabellennamen, Spaltennamen usw. aussehen, bevor Sie sie interpolieren.

  • Escape-Ausgabe: In diesem Fall bedeutet "Ausgabe" das Einfügen von Daten in eine SQL-Abfrage. Wir verwenden Funktionen, um Variablen, die als Zeichenfolgenliterale in einem SQL-Ausdruck verwendet werden, so zu transformieren, dass Anführungszeichen und andere Sonderzeichen in der Zeichenfolge maskiert werden. Wir sollten auch Funktionen verwenden, um Variablen zu transformieren, die als Tabellennamen, Spaltennamen usw. verwendet werden. Bei anderen Syntaxen wie dem dynamischen Schreiben ganzer SQL-Ausdrücke ist dies ein komplexeres Problem.

Bill Karwin
quelle
12

In diesem Thread scheint es einige Verwirrung über die Definition einer "parametrisierten Abfrage" zu geben.

  • SQL wie ein gespeicherter Prozess, der Parameter akzeptiert.
  • SQL, das mithilfe der DBMS-Parametersammlung aufgerufen wird.

In Anbetracht der früheren Definition zeigen viele der Links funktionierende Angriffe.

Aber die "normale" Definition ist die letztere. Angesichts dieser Definition kenne ich keinen SQL-Injection-Angriff, der funktionieren würde. Das heißt nicht, dass es keinen gibt, aber ich muss es noch sehen.

Aus den Kommentaren geht hervor, dass ich mich nicht klar genug ausdrücke. Hier ist ein Beispiel, das hoffentlich klarer wird:

Dieser Ansatz ist offen für SQL-Injection

exec dbo.MyStoredProc 'DodgyText'

Dieser Ansatz ist für die SQL-Injection nicht offen

using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
    newParam.Value = "DodgyText";
    .....
    cmd.Parameters.Add(newParam);
    .....
    cmd.ExecuteNonQuery();
}
HTTP 410
quelle
Können Sie klarstellen, was Sie unter der DBMS-Parametersammlung verstehen, im Gegensatz zu einer Prozedur, die Parameter akzeptiert?
Rune Grimstad
Rune, lesen Sie den Abschnitt " Typensichere
HTTP 410
Meine Antwort war auf Runes ursprüngliche Frage, bevor sie mit dem Update bearbeitet wurde.
Mikekidder
Ich habe diesen msdn-Artikel über SQL-Injection gelesen und erneut gelesen und sehe immer noch keinen Unterschied zwischen den Parametern einer gespeicherten Prozedur und den Parametern einer dynamischen Abfrage. Abgesehen von der Tatsache, dass dynamische Abfragen dynamisch sind. Sie müssen die Parameter noch binden, oder?
Rune Grimstad
Es ist die Bindung, die den Unterschied macht. Wenn Sie einen gespeicherten Prozess mit Parametern direkt aufrufen, wird keine Eingabefilterung durchgeführt. Wenn Sie jedoch (zum Beispiel) mithilfe der SqlCommand-Parametersammlung in .NET binden, werden alle Parameter gefiltert und als einfacher Text behandelt.
HTTP 410
10

Jeder SQL-Parameter vom Typ String (varchar, nvarchar usw.), der zum Erstellen einer dynamischen Abfrage verwendet wird, ist weiterhin anfällig

Andernfalls sollte die Konvertierung des Parametertyps (z. B. in int, decimal, date usw.) jeden Versuch verhindern, SQL über den Parameter einzufügen

BEARBEITEN: Ein Beispiel, in dem Parameter @ p1 ein Tabellenname sein soll

create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) ) 
AS
    SET NOCOUNT ON
    declare @sql varchar(512)
    set @sql = 'select * from ' + @p1
    exec(@sql)
GO

Wenn @ p1 aus einer Dropdown-Liste ausgewählt ist, handelt es sich um einen potenziellen SQL-Injection-Angriffsvektor.

Wenn @ p1 programmgesteuert formuliert wird, ohne dass der Benutzer eingreifen kann, handelt es sich nicht um einen potenziellen Angriffsvektor für die SQL-Injektion

Steven A. Lowe
quelle
Nein; Der springende Punkt ist, dass die an das DBMS übergebene Zeichenfolge nicht Teil der SQL-Anweisung ist. Daher hat der Wert in der Zeichenfolge keinen Einfluss auf die Interpretation des SQL - nur auf die Werte, auf die das SQL verweist.
Jonathan Leffler
So sehe ich auch Parameter. Sie sollen dieses Problem verhindern.
Rune Grimstad
2
Steven hat Recht, wenn Sie beispielsweise einen String an einen sp übergeben, der ihn zum Ausführen von sp_executeSql (SQL Server) verwendet, besteht immer noch ein SQL-Injection-Risiko.
Alexmac
@Steven: Das ist kein Parameter für SQL. Anstelle der Zeichenfolgenverkettung müsste ein Platzhalter (Fragezeichen) vorhanden sein. In SQL können Sie den Tabellennamen nicht nach Platzhalter angeben. Das ist eine reine SQL-Injection-Schwachstelle - das ursprüngliche Problem.
Jonathan Leffler
@Steven: Vielleicht wurde der Begriff 'Parameter' einmal zu oft überladen. : D
Jonathan Leffler
6

Ein Pufferüberlauf ist keine SQL-Injection.

Parametrisierte Abfragen garantieren, dass Sie vor SQL-Injection geschützt sind. Sie garantieren nicht, dass es keine möglichen Exploits in Form von Fehlern in Ihrem SQL Server gibt, aber nichts wird dies garantieren.

Blorgbeard ist raus
quelle
2

Ihre Daten sind nicht sicher, wenn Sie dynamisches SQL in irgendeiner Form verwenden, da sich die Berechtigungen auf Tabellenebene befinden müssen. Ja, Sie haben die Art und das Ausmaß des Injektionsangriffs durch diese bestimmte Abfrage begrenzt, aber nicht den Zugriff, den ein Benutzer erhalten kann, wenn er oder sie einen Weg in das System findet, und Sie sind für interne Benutzer, die auf das zugreifen, was sie nicht sollten, völlig gefährdet um Betrug zu begehen oder persönliche Informationen zu stehlen, um sie zu verkaufen. Dynamisches SQL jeglicher Art ist eine gefährliche Praxis. Wenn Sie nicht dynamisch gespeicherte Prozesse verwenden, können Sie Berechtigungen auf Prozedurebene festlegen, und kein Benutzer kann etwas anderes tun als das, was durch die Prozesse definiert ist (außer natürlich Systemadministratoren).

HLGEM
quelle
Die Lektion hier lautet also: Wenn Sie dynamisches SQL verwenden müssen, tun Sie dies nur innerhalb einer gespeicherten Prozedur. +1 guter Rat!
Steven A. Lowe
1
No-Dynamic SQL in gespeicherten Prozessen kann weiterhin SQL-Injection-Fehler verursachen, indem nicht validierte Daten in die dynamische Abfrage interpoliert werden.
Bill Karwin
Nein, die Lektion hier ist, niemals dynamisches SQl
HLGEM zu verwenden.
@HLGEM - richtig, und Autos sind in Verkehrsunfälle verwickelt, deshalb sollten wir niemals Autos benutzen.
Bill Karwin
Dynamisches SQL in einem gespeicherten Prozess wird jedoch (standardmäßig) mit der Erlaubnis des Aufrufers ausgeführt, nicht wie statisches SQL, das mit der Erlaubnis des Besitzers des gespeicherten Prozesses ausgeführt wird. Dies ist eine wichtige Unterscheidung.
HTTP 410
1

Es ist möglich, dass ein gespeicherter Prozess durch Überlauf / Abschneiden für bestimmte Arten der SQL-Injection anfällig ist. Siehe: Injection Enabled by Data Truncation hier:

http://msdn.microsoft.com/en-us/library/ms161953.aspx

Booji Boy
quelle
Wenn Sie den Artikel ausführlich lesen, werden Sie feststellen, dass die Verwendung der Parametersammlung von SQL Server diesen Angriff verhindert. Und das ist die normale Definition einer "parametrisierten Abfrage" - sie verwendet die Parameters-Auflistung des DBMS.
HTTP 410
1

Denken Sie daran, dass Sie mit Parametern die Zeichenfolge einfach speichern oder den Benutzernamen sagen können, wenn Sie keine Richtlinien haben. "); Tabellenbenutzer löschen; -"

Dies an sich verursacht keinen Schaden, aber Sie wissen besser, wo und wie dieses Datum weiter unten in Ihrer Anwendung verwendet wird (z. B. in einem Cookie gespeichert, später abgerufen, um andere Aufgaben zu erledigen.

nr
quelle
1

Sie können als Beispiel dynamisches SQL ausführen

DECLARE @SQL NVARCHAR(4000);
DECLARE @ParameterDefinition NVARCHAR(4000);

SELECT  @ParameterDefinition = '@date varchar(10)'

SET @SQL='Select CAST(@date AS DATETIME) Date'

EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'
Mohamed Abbas
quelle