Frage

Wenn ich aus einer Tabelle eine Zeile auszuwählen waren im Grunde zwei Möglichkeiten habe ich, entweder wie diese

int key = some_number_derived_from_a_dropdown_or_whatever
SqlCommand cmd = new SqlCommand("select * from table where primary_key = " + key.ToString());

oder einen Parameter

SqlCommand cmd = new SqlCommand("select * from table where primary_key = @pk");
SqlParameter param  = new SqlParameter();
param.ParameterName = "@pk";
param.Value         = some_number_derived_from_a_dropdown_or_whatever;
cmd.Parameters.Add(param);

Nun, ich weiß, die erste Methode auf, wegen möglicher SQL-Injection-Angriffe verpönt, aber in diesem Fall ist der Parameter ist eine ganze Zahl ist und somit nicht wirklich möglich sein sollte, bösartigen Code zu injizieren.

Meine Frage ist: Sie Option 1 im Produktionscode verwenden Sie, weil Sie die Verwendung sicher aufgrund der einfachen Bedienung und Kontrolle über die eingesetzten Parameter (wie die oben, oder wenn der Parameter erstellt im Code) in Betracht ziehen? Oder verwenden Sie immer Parameter, egal was? Sind Parameter 100% Injektion sicher?

War es hilfreich?

Lösung

Ich werde das SQL-Injection-Argument überspringen, das nur zu gut bekannt ist und nur konzentriere sich auf dem SQL-Aspekte von Parametern im Vergleich zu nicht-Parametern.

Wenn Sie eine SQL-Batch an den Server senden, jede Charge, hat sie analysiert werden begriffen werden. Wie bei jedem anderen Compiler haben die SQL-Compiler einen AST aus dem Text zu erzeugen, und dann arbeiten auf Syntaxbaum. Letztlich wandelt sich das Optimierungsprogramm den Syntaxbaum in einer Baumausführung und schließlich erzeugt einen Ausführungsplan und das ist tatsächlich auszuführen. Zurück in den dunklen Zeiten der circa 1995 machte es einen Unterschied, ob die Charge eine Ad-hoc-Abfrage oder eine gespeicherte Prozedur war, aber heute macht es absolut keine, sie alle gleich.

Jetzt, wo Parameter ein Unterschied besteht darin, dass ein Client, der eine Abfrage wie select * from table where primary_key = @pk sendet sendet genau die gleiche SQL-Text jedes Mal, egal, was Wert ist interessiert. Was dann passiert, ist, dass die gesamte Prozess, den ich oben beschrieben ist kurzgeschlossen. SQL wird in Speicher einen Ausführungsplan für die rohen, unparsed, Text suchen sie empfangen (basierend auf einer Hash-Digest des Eingangs) und, falls gefunden wird, diesen Plan auszuführen. Das bedeutet kein Parsing, keine Optimierung, nichts, der Ansatz geht gerade in Ausführung . Auf OLTP-Systemen, die Hunderte und Tausende von kleinen Anfragen pro Sekunde, dies schneller Weg macht einen großen Unterschied in der Leistung führen.

Wenn Sie die Abfrage in Form select * from table where primary_key = 1 senden dann SQL müssen mindestens analysieren, sie zu verstehen, was in dem Text ist, da der Text wahrscheinlich eine neue ist, unterscheidet sich von allen vorherigen Charge es (auch nur ein einziges Zeichen gesehen wie 1 vs. 2 macht die gesamte Charge unterschiedlich). Es wird dann auf dem resultierenden Syntaxbaum arbeiten und einen Prozess versuchen, genannt Einfache Parametrisierung . Wenn die Abfrage Auto-paremeterized sein kann, dann wird SQL wahrscheinlich einen zwischengespeicherte Ausführungsplan für sie von anderen Abfragen finden, die zuvor mit anderen pk Werten laufen und diesen Plan wieder verwenden, so dass zumindest Ihre Abfrage nicht optimiert werden muss und Sie überspringen die Schritt einen tatsächlichen Ausführungsplan zu erzeugen. Aber keine leichte haben Sie die komplette Kurzschluss zu erreichen, der kürzest möglichen Weg Sie erreichen mit einem echten Client parametrisierte Abfrage.

Sie können schauen in die SQL Server, SQL-Statistik Object Leistungsindikator Ihres Servers. Der Zähler Auto-Param Attempts/sec viele Male pro Sekunde zeigen SQL eine Abfrage ohne Parameter in eine Auto-parametrisierte einer empfangenen übersetzen muss. Jeder Versuch kann vermieden werden, wenn Sie richtig die Abfrage im Client parametrieren. Wenn Sie auch eine hohe Anzahl von Failed Auto-Params/sec haben, ist noch schlimmer, es bedeutet, dass die Abfragen den gesamten Zyklus der Optimierung und Ausführungsplan Generation werden.

Andere Tipps

Verwenden Sie immer die Option 2).

Die erste ist nicht sicher in Bezug auf SQL-Injection-Angriffe .

Die zweite ist nicht nur viel sicherer, sondern auch ein bessere Leistung, da die Abfrage-Optimierer bessere Chancen haben einen guten Abfrageplan für sie, da die Abfrage Aussehen zu erstellen das gleiche die ganze Zeit, erwarten die Parameter natürlich.

Warum sollten Sie Option 1

vermeiden

Auch wenn es scheint, dass Sie diesen Wert von select Elemente bekommen, könnte jemand gefälschte eine HTTP-Anfrage und nach, was sie in bestimmten Bereichen wollen. Ihr Code in Option 1 sollte mindestens ersetzen einige gefährliche Zeichen / Kombinationen (dh. Einfache Anführungszeichen, eckige Klammern usw.).

Warum sind Sie Option 2

verwendet werden ermutigt

SQL-Abfrage-Engine ist der Cache-Ausführungsplan der Lage und die Verwaltung von Statistiken für verschiedene Abfragen auf sie geworfen. So vereinigt haben Abfragen (das beste wäre natürlich eine separate gespeicherte Prozedur haben) beschleunigt die Ausführung auf lange Sicht.

Ich habe noch von jedem Beispiel zu hören, bei dem die Parameter für SQL-Injection gekapert werden. Bis ich es das Gegenteil bewiesen ist zu sehen, würde ich halte sie für sicher.

Dynamische SQL sollte nie als sicher angesehen werden. Auch mit „trusted“ Eingang, es ist eine schlechte Angewohnheit, in zu erhalten. Beachten Sie, dass diese in gespeicherten Prozeduren dynamische SQL enthält; SQL-Injektion kann es auch auftreten.

Weil Sie die Kontrolle haben, dass der Wert eine ganze Zahl ist, sind sie so ziemlich gleichwertig. Ich benutze im Allgemeinen nicht die erste Form, und in der Regel, ich nicht zulassen, dass die zweite entweder, weil ich in der Regel nicht den Tabellenzugriff erlauben und erfordern die Verwendung von Stored Procedures. Und obwohl Sie können ohne Verwendung der Parameter Sammlung SP Ausführung tun, empfehle ich immer noch SPs mit und Parameter:

-- Not vulnerable to injection as long as you trust int and int.ToString()
int key = some_number_derived_from_a_dropdown_or_whatever ;
SqlCommand cmd = new SqlCommand("EXEC sp_to_retrieve_row " + key.ToString()); 

-- Vulnerable to injection all of a sudden
string key = some_number_derived_from_a_dropdown_or_whatever ;
SqlCommand cmd = new SqlCommand("EXEC sp_to_retrieve_row " + key.ToString()); 

Beachten Sie, dass, obwohl die Option 1 ist sicher in Ihrem Fall , was passiert, wenn jemand sieht und nutzt diese Technik mit einer nicht-ganzzahligen Variablen - jetzt Sie Menschen trainieren, eine Technik zu verwenden, die sein könnte offen Injektion.

Beachten Sie, dass Sie proaktiv Ihre Datenbank Injektion zu vermeiden aushärten kann auch wirksam sein, wenn die Anwendung Code fehlerhaft ist. Für Konten / Rollen, die Anwendungen verwenden:

  • erlaubt nur den Zugriff auf Tabellen als unbedingt erforderlich
  • erlaubt nur den Zugriff auf Ansichten, wie unbedingt erforderlich
  • Nicht in DDL-Anweisungen
  • Lassen Sie zu SPs auf Rolle Basis ausführen
  • Jede dynamische SQL in SPs sollte unbedingt erforderlich
  • überprüft werden

Persönlich würde ich immer die Option 2 als eine Frage der Gewohnheit verwenden. Dass gesagt wird:

Da Sie die Konvertierung aus dem Dropdown-Wert in einen int zwingen, die einen gewissen Schutz vor SQL-Injection-Angriffe bieten. Es jemand versucht, zusätzliche Informationen in die geposteten Informationen zu injizieren, wird C # eine Ausnahme aus, wenn man versucht, den Schadcode in einen ganzzahligen Wert zu vereiteln, den Versuch zu konvertieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top