SQL-Injection ist ein sehr schwerwiegendes Sicherheitsproblem, zum großen Teil, weil es so einfach ist, es falsch zu machen: Die offensichtliche, intuitive Art, eine Abfrage mit Benutzereingaben zu erstellen, macht Sie anfällig, und die richtige Art, dies zu verringern, erfordert, dass Sie über Parameter informiert sind Abfragen und SQL-Injection zuerst.
Mir scheint, dass der offensichtliche Weg, dies zu beheben, darin besteht, die offensichtliche (aber falsche) Option auszuschalten: Korrigieren Sie das Datenbankmodul, sodass jede Abfrage, die hartcodierte Werte in der WHERE-Klausel anstelle von Parametern verwendet, eine nette, beschreibende zurückgibt Fehlermeldung, die Sie auffordert, stattdessen Parameter zu verwenden. Dies würde natürlich eine Deaktivierungsoption erfordern, damit Dinge wie Ad-hoc-Abfragen von Verwaltungstools weiterhin problemlos ausgeführt werden können, sie sollte jedoch standardmäßig aktiviert sein.
Wenn dies der Fall wäre, würde die SQL-Injection fast über Nacht heruntergefahren, aber meines Wissens macht dies kein RDBMS. Gibt es einen guten Grund, warum nicht?
bad_ideas_sql = 'SELECT title FROM idea WHERE idea.status == "bad" AND idea.user == :mwheeler'
Hätte in einer einzigen Abfrage sowohl fest codierte als auch parametrisierte Werte - versuchen Sie das zu fangen! Ich denke, es gibt gültige Anwendungsfälle für solche gemischten Abfragen.SELECT * FROM jokes WHERE date > DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY score DESC;
"bad"
wirklich ein Literal ist oder aus der Verkettung von Zeichenfolgen resultiert. Die beiden Lösungen, die ich sehe, sind, entweder SQL und andere in Strings eingebettete DSLs zu entfernen (ja, bitte) oder Sprachen zu fördern, bei denen die Verkettung von Strings ärgerlicher ist als die Verwendung parametrisierter Abfragen (umm, nein).Antworten:
Es gibt zu viele Fälle, in denen ein Literal der richtige Ansatz ist.
Vom Standpunkt der Leistung aus gibt es Zeiten, in denen Sie Literale in Ihren Abfragen benötigen. Stellen Sie sich vor, ich habe einen Bug-Tracker, bei dem 70% der Fehler im System "geschlossen", 20% "offen", 5% "aktiv" und 5% der Fehler "aktiv" sind, sobald sie groß genug sind, um die Leistung zu beeinträchtigen % hat einen anderen Status. Ich möchte vielleicht vernünftigerweise die Abfrage haben, die alle aktiven Bugs zurückgibt
anstatt die
status
als Bindevariable zu übergeben. Ich möchte einen anderen Abfrageplan in Abhängigkeit vom übergebenen Wert fürstatus
- Ich möchte einen Tabellenscan durchführen, um die geschlossenen Bugs und einen Indexscan für die zurückzusendenstatus
Spalte, um die aktiven Kredite zurückzugeben. Unterschiedliche Datenbanken und unterschiedliche Versionen haben unterschiedliche Ansätze, um (mehr oder weniger erfolgreich) derselben Abfrage die Verwendung eines unterschiedlichen Abfrageplans abhängig vom Wert der Bindungsvariablen zu ermöglichen. Dies führt jedoch in der Regel zu einer erheblichen Komplexität, die verwaltet werden muss, um die Entscheidung auszugleichen, ob ein erneutes Parsen einer Abfrage oder die Wiederverwendung eines vorhandenen Plans für einen neuen Bindevariablenwert erforderlich ist. Für einen Entwickler kann es sinnvoll sein, mit dieser Komplexität umzugehen. Oder es kann sinnvoll sein, einen anderen Pfad zu erzwingen, wenn ich mehr Informationen darüber habe, wie meine Daten aussehen werden, als der Optimierer.Unter dem Gesichtspunkt der Codekomplexität ist es auch häufig sinnvoll, Literale in SQL-Anweisungen zu haben. Wenn Sie zum Beispiel eine
zip_code
Spalte mit einer 5-stelligen Postleitzahl und manchmal weiteren 4 Stellen haben, ist es vollkommen sinnvoll, so etwas zu tunanstatt 4 separate Parameter für die numerischen Werte einzugeben. Dies sind keine Dinge, die sich jemals ändern werden, sodass das Binden von Variablen nur dazu dient, den Code potenziell schwerer lesbar zu machen und das Potenzial zu schaffen, dass jemand Parameter in der falschen Reihenfolge bindet und einen Fehler verursacht.
quelle
SQL Injection tritt auf, wenn eine Abfrage erstellt wird, indem Text aus einer nicht vertrauenswürdigen und nicht validierten Quelle mit anderen Teilen einer Abfrage verknüpft wird. Während so etwas am häufigsten bei String-Literalen vorkommt, ist dies nicht der einzige Weg, wie es vorkommen könnte. Eine Abfrage für numerische Werte könnte eine vom Benutzer eingegebene Zeichenkette übernehmen (das sollte nur Ziffern enthalten) und verketten mit anderem Material eine Abfrage ohne die Anführungszeichen normalerweise mit Stringliterale assoziiert zu bilden; Code, der der clientseitigen Validierung zu sehr vertraut, enthält möglicherweise Feldnamen, die aus einer HTML-Abfragezeichenfolge stammen. Code, der eine SQL-Abfragezeichenfolge betrachtet, kann nicht erkennen, wie sie zusammengestellt wurde.
Wichtig ist nicht, ob eine SQL-Anweisung Zeichenfolgenliterale enthält, sondern ob eine Zeichenfolge Zeichenfolgen aus nicht vertrauenswürdigen Quellen enthält . Die Validierung hierfür sollte am besten in der Bibliothek erfolgen, die Abfragen erstellt. In C # gibt es im Allgemeinen keine Möglichkeit, Code zu schreiben, der ein Zeichenfolgenliteral zulässt, andere Arten von Zeichenfolgenausdrücken jedoch nicht zulässt. Es kann jedoch eine Codierungsregel geben, die erfordert, dass Abfragen mithilfe einer abfrageerstellenden Klasse erstellt werden Die Verkettung von Zeichenfolgen und die Übergabe einer nicht-wörtlichen Zeichenfolge an den Abfrage-Generator müssen eine solche Aktion rechtfertigen.
quelle
Wenn Sie die Ergebnisse in die Fußzeile Ihres Forums einfügen möchten, müssen Sie einen Dummy-Parameter hinzufügen, um jedes Mal false zu sagen. Oder der naive Web-Programmierer sucht nach Informationen zum Deaktivieren dieser Warnung und fährt dann fort.
Jetzt können Sie sagen, dass Sie eine Ausnahme für Aufzählungen hinzufügen würden, die jedoch das Loch wieder öffnet (obwohl es kleiner ist). Ganz zu schweigen von Menschen, die erst erzogen werden müssen, um sie nicht zu benutzen
varchars
.Das eigentliche Problem bei der Injektion ist die programmgesteuerte Erstellung der Abfragezeichenfolge. Die Lösung hierfür ist ein Mechanismus für gespeicherte Prozeduren und die Durchsetzung seiner Verwendung oder eine Whitelist zulässiger Abfragen.
quelle
deleted = false
mitNOT deleted
, die die wörtliche vermeidet. Aber der Punkt ist im Allgemeinen gültig.TL; DR : Sie müssten alle Literale einschränken , nicht nur die in
WHERE
Klauseln. Aus Gründen, aus denen sie dies nicht tun, kann die Datenbank von anderen Systemen entkoppelt bleiben.Erstens ist Ihre Prämisse fehlerhaft. Sie möchten nur
WHERE
Klauseln einschränken , aber dies ist nicht der einzige Ort, an dem Benutzereingaben möglich sind. Beispielsweise,Dies ist gleichermaßen anfällig für SQL-Injection:
Sie können also nicht nur Literale in der Liste einschränken
WHERE
Klausel . Sie müssen alle Literale einschränken .Jetzt bleibt die Frage: "Warum überhaupt Literale zulassen?" Beachten Sie Folgendes: Während relationale Datenbanken unter einer Anwendung verwendet werden, die in einer anderen Sprache geschrieben ist, ist es nicht erforderlich, dass Sie Anwendungscode verwenden, um die Datenbank zu verwenden. Und hier haben wir eine Antwort: Sie brauchen Literale, um Code zu schreiben. Die einzige Alternative wäre, den gesamten Code in einer von der Datenbank unabhängigen Sprache zu schreiben. Wenn Sie sie haben, können Sie "Code" (SQL) direkt in die Datenbank schreiben. Dies ist eine wertvolle Entkopplung und ohne Literale nicht möglich. (Versuchen Sie, irgendwann ohne Literale in Ihrer Lieblingssprache zu schreiben. Ich bin sicher, Sie können sich vorstellen, wie schwierig das sein würde.)
In der Grundgesamtheit von Wertelisten- / Nachschlagetabellen werden häufig Literale verwendet:
Ohne sie müssten Sie Code in einer anderen Programmiersprache schreiben , um diese Tabelle zu füllen. Die Möglichkeit, dies direkt in SQL zu tun, ist wertvoll .
Dann bleibt uns noch eine Frage: Warum machen Programmiersprachen-Client-Bibliotheken das dann nicht? Und hier haben wir eine sehr einfache Antwort: Sie hätten den gesamten Datenbankparser für jede unterstützte Version der Datenbank erneut implementiert . Warum? Weil es keinen anderen Weg gibt, um zu garantieren, dass Sie jedes Wort gefunden haben. Reguläre Ausdrücke sind nicht genug. Zum Beispiel: Dies enthält 4 separate Literale in PostgreSQL:
Dies zu versuchen, wäre ein Alptraum für die Wartung, zumal sich die gültige Syntax häufig zwischen den Hauptversionen von Datenbanken ändert.
quelle