Ist es sicher, eine SQL-Abfrage nicht zu parametrisieren, wenn der Parameter keine Zeichenfolge ist?

113

In Bezug auf die SQL-Injection verstehe ich die Notwendigkeit, einen stringParameter zu parametrisieren, vollständig . Das ist einer der ältesten Tricks im Buch. Aber wann kann es gerechtfertigt sein, eine nicht zu parametrisieren SqlCommand? Werden Datentypen als "sicher" angesehen, um nicht parametrisiert zu werden?

Zum Beispiel: Ich habe mich nicht überall betrachte in der Nähe von einem Experten in SQL, aber ich kann die Fälle nicht denken , wo es potenziell anfällig für SQL - Injection wäre ein zu akzeptieren booloder ein intund verketten es nur nach rechts in die Abfrage.

Ist meine Annahme richtig oder könnte dies möglicherweise eine große Sicherheitslücke in meinem Programm hinterlassen?

Zur Verdeutlichung ist diese Frage markiert das ist eine stark typisierte Sprache; Wenn ich "Parameter" sage, denke ich an etwas wie public int Query(int id) .

johnnyRose
quelle
14
Sie können nicht von zwischengespeicherten Abfrageplänen profitieren, wenn Sie keine Parameter verwenden. Für jede neue Kombination von Eingaben, die Sie bereitstellen, muss ein separater Abfrageplan erstellt werden.
Scott Chamberlain
5
@MatthewWhited Woher weißt du, dass es weniger Zeit braucht? Diese Situation tritt in bestimmten Projekten eines aktuellen Entwicklers und eines früheren Entwicklers überall auf. Wenn dies die Sicherheit tatsächlich verbessert, geben Sie bitte eine Antwort. Zur Verdeutlichung stimme ich zu, dass es offensichtlich besser ist, zu parametrisieren. Aber das ist nicht wirklich meine Frage.
Johnny Rose
7
Parametrisierte Abfragen werden hauptsächlich zur Leistung und Optimierung verwendet. SQL Injection Prevention ist ein Nebeneffekt.
Salman A
13
Ich denke, das OP hat eine gültige Frage gestellt. Er versucht, Kosten / Nutzen der Festlegung eines potenziellen Risikos zu bewerten. Diese Gleichung ändert sich mit dem Potenzial dieses Risikos. Wenn es kein Risiko gibt, würde ich es auch nicht tun. Er hat nach einer technischen Frage zum Potenzial gefragt, nicht nach einer subjektiven Beurteilung, ob es Ihrer Meinung nach seine Zeit wert ist. Das OP ist der einzige, der diesen Anruf tätigen kann.
Sir Swears-a-lot
10
Um mich zu erklären: Ich bin ein dba. Ich schätze und respektiere Best Practices und in einer perfekten Welt wäre jeder Code perfekt. Leider habe ich in der Welt, in der ich arbeite, mehr Probleme zu lösen, als ich Zeit habe, um sie zu lösen. Das bedeutet Priorisierung. IMO Rewriting-Code, der bereits funktioniert, sicher ist und ein akzeptables Niveau aufweist, klingt nach Luxus. (Das kann ich mir nicht leisten)
Sir schwört viel

Antworten:

101

Ich denke, es ist sicher ... technisch gesehen , aber es ist eine schreckliche Angewohnheit, sich darauf einzulassen. Möchten Sie wirklich solche Abfragen schreiben?

var sqlCommand = new SqlCommand("SELECT * FROM People WHERE IsAlive = " + isAlive + 
" AND FirstName = @firstName");

sqlCommand.Parameters.AddWithValue("firstName", "Rob");

Sie sind auch in Situationen anfällig, in denen sich ein Typ von einer Ganzzahl in eine Zeichenfolge ändert (denken Sie an die Mitarbeiternummer, die trotz ihres Namens möglicherweise Buchstaben enthält).

Wir haben den Typ der EmployeeNumber von intin geändert string, aber vergessen, unsere SQL-Abfragen zu aktualisieren. Hoppla.

Rob
quelle
24
Können wir schon aufhören zu benutzen AddWithValue ? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…
RemarkLima
5
@RemarkLima Was ist die Lösung, wenn Sie dynamisch Code generieren, der Werte Parametern zuordnet? Der Blog-Beitrag geht nicht auf dieses Szenario ein. Ja, es ist eine einzelne Zeile, um den SQL-Typ festzulegen, wenn er bekannt ist. Wenn dies nicht der Fall ist, liegt ein Problem vor (oder Sie müssen Modelle mit diesen Informationen mit Anmerkungen versehen).
CasperOne
1
Dann bleiben Sie hängen, es AddWithValuesei denn, Sie haben eine Zuordnung von Datenbanktypen als Teil des dynamischen Aufbaus der Anweisung. Ich würde annehmen, dass Sie eine Liste von Zielspalten haben und als Teil des Wörterbuchs die Typen haben könnten, wenn Sie möchten. Ansonsten nimm einfach den Performance-Hit. Letztendlich ist es nur eine gute Information zu wissen, denke ich.
RemarkLima
8
@RemarkLima Der Punkt ist "Können wir schon aufhören zu benutzen AddWithValue?" sollte wirklich sein "wenn Sie den Typ kennen, dann sollten Sie auf die Verwendung verzichten AddWithValue.
casperOne
2
Hey, schieß nicht auf den Messenger, ich habe ihn nicht geschrieben ;-), aber der Punkt bleibt, und wenn du von Anfang an in deine Designs eingebaut bist, gibt es keinen Grund, warum du den Typ nicht kennen solltest. Best Practice und all dieser Jazz :-)
RemarkLima
65

Wenn eine stark typisierte Plattform auf einem Computer mit Ihnen (wie ein Web - Server) zu steuern, können Sie Code - Injektion für Abfragen mit nur verhindern bool, DateTimeoder int(und anderen numerischen) Werten. Was Anlass zur Sorge gibt, sind Leistungsprobleme, die dadurch verursacht werden, dass SQL Server gezwungen wird, jede Abfrage neu zu kompilieren, und verhindert wird, dass gute Statistiken darüber abgerufen werden, welche Abfragen mit welcher Häufigkeit ausgeführt werden (was die Cache-Verwaltung beeinträchtigt).

Dieser Teil "Auf einem Computer, den Sie steuern" ist jedoch wichtig, da ein Benutzer andernfalls das Verhalten des Systems zum Generieren von Zeichenfolgen aus diesen Werten ändern kann, um beliebigen Text einzuschließen.

Ich denke auch gerne langfristig. Was passiert, wenn die heutige altmodische, stark typisierte Codebasis über die automatische Übersetzung in die dynamische Sprache der neuen Aktualität portiert wird und Sie plötzlich die Typprüfung verlieren, aber noch nicht die richtigen Komponententests für den dynamischen Code haben? ?

Es gibt wirklich keinen guten Grund, keine Abfrageparameter für diese Werte zu verwenden. Es ist der richtige Weg, dies zu tun. Gehen Sie voran und codieren Sie Werte fest in die SQL-Zeichenfolge, wenn sie wirklich Konstanten sind. Andernfalls sollten Sie einen Parameter verwenden. Es ist nicht so, als wäre es schwer.

Letztendlich würde ich dies nicht per se als Fehler bezeichnen , aber ich würde es als Geruch bezeichnen : etwas, das für sich genommen nur knapp unter einem Fehler liegt, aber ein starkes Indiz dafür ist, dass Fehler in der Nähe sind oder irgendwann auftreten werden. Guter Code vermeidet es, Gerüche zu hinterlassen, und jedes gute statische Analysewerkzeug weist darauf hin.

Ich werde hinzufügen, dass dies leider nicht die Art von Argument ist, die Sie direkt gewinnen können. Es klingt nach einer Situation, in der es nicht mehr ausreicht, "richtig" zu sein, und wenn Sie Ihren Mitarbeitern auf die Zehen treten, um dieses Problem selbst zu beheben, wird dies wahrscheinlich keine gute Teamdynamik fördern. es könnte letztendlich mehr weh tun als es hilft. Ein besserer Ansatz in diesem Fall könnte darin bestehen, die Verwendung eines statischen Analysewerkzeugs zu fördern. Dies würde den Bemühungen, die darauf abzielen und zurückgehen und vorhandenen Code reparieren, Legitimität und Glaubwürdigkeit verleihen.

Joel Coehoorn
quelle
1
Es ist definitiv keine Herausforderung, es parametrisiert zu machen. Meine Frage stellte sich, weil ein Mitarbeiter eine Reihe von Abfragen schrieb, die ganzzahlige Werte verketteten, und ich mich fragte, ob es Zeitverschwendung war, alle durchzugehen und zu beheben.
Johnny Rose
2
Ich denke, die Frage "Ist es ein Fehler?" Ist das, worauf meine Frage hinausläuft.
Johnny Rose
7
Es ist ein "Geruch": etwas, das von sich aus hinter einem Fehler zurückbleibt, aber darauf hinweist, dass Fehler wahrscheinlich in der Nähe sind. Guter Code versucht, Gerüche zu beseitigen. Jedes gute statische Analysewerkzeug würde es definitiv kennzeichnen.
Joel Coehoorn
1
Ich mag den Begriff "Geruch". Ich hätte stattdessen so etwas wie "Larve" verwendet, wo es noch kein Fehler ist, aber zukünftige Updates könnten es zu einer Made machen, die an Ihrem Backend frisst, bis Sie es zerdrücken oder begasen. Sie möchten sicher nicht, dass das Potenzial für nekrotischen Code in einer Produktionsumgebung auftaucht, und etwas, das nicht mit einem gewissen Maß an Finesse entwickelt wurde, kann dazu führen, dass dies vorhanden ist, wie in diesem Fall.
CSS
1
Das ist einfach falsch. Siehe meine Antwort zum Beispiel, wie Sie noch SQL-Injection mit DateTimeoderint
Kaspars Ozols
53

In einigen Fällen ist es möglich, einen SQL-Injection-Angriff mit anderen nicht parametrisierten (verketteten) Variablen als Zeichenfolgenwerten durchzuführen - siehe diesen Artikel von Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -Kultur / .

Beim Aufrufen ToStringkann ein benutzerdefinierter Kulturanbieter einen Nicht-String-Parameter in seine String-Darstellung umwandeln, wodurch SQL in die Abfrage eingefügt wird.

Maciek
quelle
14
Ich denke, dies ist der einzige Beitrag, der die Frage beantwortet: "Wie kann eine Injektion überhaupt mit ints möglich sein ?"
Arturo Torres Sánchez
3
Wenn Sie jedoch in der Lage sind, benutzerdefinierten Code wie Sprengfallen einzufügen, ist es CultureInfoschwierig zu wissen, warum Sie ohnehin eine SQL-Injektion benötigen würden.
Martin Smith
plus 1, die einzige Antwort, die tatsächlich die Frage beantwortet
ken2k
@MartinSmith: Siehe meine Antwort, die einen möglichen Weg zeigt, CultureInfo von außen zu ändern.
user1027167
Wenn eine Person solchen Code in einer Anwendung schreiben kann, warum benötigt sie dann SQL Injection?
Reza Aghaei
51

Dies ist selbst für Nicht-String-Typen nicht sicher. Verwenden Sie immer Parameter. Zeitraum.

Betrachten Sie folgendes Codebeispiel:

var utcNow = DateTime.UtcNow;
var sqlCommand = new SqlCommand("SELECT * FROM People WHERE created_on <= '" + utcNow + "'");

Auf den ersten Blick sieht Code sicher aus, aber alles ändert sich, wenn Sie einige Änderungen in den regionalen Windows-Einstellungen vornehmen und die Injektion im Kurzdatumsformat hinzufügen:

Datetime Injection

Der resultierende Befehlstext sieht nun folgendermaßen aus:

SELECT * FROM People WHERE created_on <= '26.09.2015' OR '1'<>' 21:21:43'

Dies gilt auch für den intTyp, da der Benutzer ein benutzerdefiniertes negatives Vorzeichen definieren kann, das leicht in SQL Injection geändert werden kann.

Man könnte argumentieren, dass eine invariante Kultur anstelle der aktuellen Kultur verwendet werden sollte, aber ich habe so oft Zeichenfolgenverkettungen gesehen, und es ist ziemlich leicht zu übersehen, wenn Zeichenfolgen mit Objekten verkettet werden +.

Kaspars Ozole
quelle
10
Wer kann die Servereinstellungen ändern? Wenn eine Person dies auf Ihrem Server tun kann, benötigt sie SQL Injection nicht, um Daten zu zerstören.
Reza Aghaei
5
Dies ist die beste Antwort. Sie zeigt einen Weg, der die Bedenken der OP bestätigt, dass es sich um einen Fehler / eine Sicherheitslücke handelt. Leistung und Zukunftssicherheit sind neben der Verkettung von Datumsangaben in SQL beispielsweise nicht nur ein Geruch oder eine technische Verschuldung . @RezaAghaei die Frage nie Server-Side erwähnt, könnte es eine Windows-App mit SQLExpress sein - so oder so ist das kein Kriterium für die Frage. Jeder kann sagen, aber wer hat Zugriff auf die Servereinstellungen, um diese hervorragende Antwort zu widerlegen, genauso wie jeder sagen kann, was ist mit Shared Server Hosting oder einem Y2K-Fehler? Ich stimme Ihnen zu, dass der Server gesperrt ist - es ist einfach keine Voraussetzung.
Jeremy Thompson
2
Können Sie ein Beispiel dafür geben, was Sie über den intTyp gesagt haben ?
Johnny Rose
1
Ich weiß, es ist ein paar Wochen her, seit Sie darauf geantwortet haben, aber könnten Sie Ihren Beitrag bearbeiten und ein Beispiel hinzufügen, wie Sie ein benutzerdefiniertes negatives Vorzeichen definieren können?
Johnny Rose
23

"SELECT * FROM Table1 WHERE Id =" + intVariable.ToString ()


Sicherheit
Es ist in Ordnung.
Angreifer können nichts in Ihre eingegebene int-Variable einfügen.

Leistung
nicht OK.

Es ist besser, Parameter zu verwenden, daher wird die Abfrage einmal kompiliert und für die nächste Verwendung zwischengespeichert. Das nächste Mal wird die Abfrage auch bei unterschiedlichen Parameterwerten zwischengespeichert und muss nicht auf dem Datenbankserver kompiliert werden.

Codierungsstil
Schlechte Praxis.

  • Parameter sind besser lesbar
  • Vielleicht gewöhnt man sich an Abfragen ohne Parameter, dann hat man vielleicht einmal einen Fehler gemacht und auf diese Weise einen String-Wert verwendet, und dann sollte man sich wahrscheinlich von seinen Daten verabschieden. Schlechte Angewohnheit!


"SELECT * FROM Product WHERE Id =" + TextBox1.Text


Es ist zwar nicht Ihre Frage, aber vielleicht nützlich für zukünftige Leser:

Sicherheitskatastrophe
!
Selbst wenn das IdFeld eine Ganzzahl ist, kann Ihre Abfrage SQL Injection unterliegen. Angenommen, Sie haben eine Abfrage in Ihrer Anwendung "SELECT * FROM Table1 WHERE Id=" + TextBox1.Text. Ein Angreifer kann sie in ein Textfeld einfügen. 1; DELETE Table1Die Abfrage lautet:

"SELECT * FROM Table1 WHERE Id=1; DELETE Table1"

Wenn Sie hier keine parametrisierte Abfrage verwenden möchten, sollten Sie typisierte Werte verwenden:

string.Format("SELECT * FROM Table1 WHERE Id={0}", int.Parse(TextBox1.Text))


Ihre Frage


Meine Frage stellte sich, weil ein Mitarbeiter eine Reihe von Abfragen schrieb, die ganzzahlige Werte verketteten, und ich mich fragte, ob es Zeitverschwendung war, alle durchzugehen und zu beheben.

Ich denke, das Ändern dieser Codes ist keine Zeitverschwendung. In der Tat wird eine Änderung empfohlen!

Wenn Ihr Mitarbeiter int-Variablen verwendet, besteht kein Sicherheitsrisiko. Ich denke jedoch, dass das Ändern dieser Codes keine Zeitverschwendung ist und dass das Ändern dieser Codes empfohlen wird. Es macht Code lesbarer, wartbarer und beschleunigt die Ausführung.

Reza Aghaei
quelle
Selbst die erste Option ist aus Sicherheitsgründen nicht ganz in Ordnung. Das Verhalten von .ToString()wird durch ein Betriebssystemkonfigurationselement bestimmt, das leicht geändert werden kann, um beliebigen Text einzuschließen.
Joel Coehoorn
18

Es gibt tatsächlich zwei Fragen in einer. Und die Frage aus dem Titel hat sehr wenig mit Bedenken zu tun, die das OP in den nachfolgenden Kommentaren geäußert hat.

Obwohl mir klar ist, dass es für das OP auf den jeweiligen Fall ankommt, ist es für die Leser von Google wichtig, die allgemeinere Frage zu beantworten, die wie folgt formuliert werden kann: "Ist die Verkettung so sicher wie vorbereitete Aussagen, wenn ich mich vergewissere?" dass jedes Literal, das ich verkette, sicher ist? ". Ich möchte mich also auf Letzteres konzentrieren. Und die Antwort ist

Auf jeden Fall NEIN.

Die Erklärung ist nicht so direkt, wie die meisten Leser es gerne hätten, aber ich werde mein Bestes geben.

Ich habe eine Weile darüber nachgedacht, was zu dem Artikel führte (obwohl er auf der PHP-Umgebung basiert), in dem ich versuchte, alles zusammenzufassen. Mir ist der Gedanke gekommen, dass die Frage des Schutzes vor SQL-Injection häufig in Bezug auf einige verwandte, aber engere Themen wie das Entweichen von Zeichenfolgen, das Casting von Typen und dergleichen nicht berücksichtigt wird. Obwohl einige der Maßnahmen für sich genommen als sicher angesehen werden können, gibt es weder ein System noch eine einfache Regel, die befolgt werden muss. Das macht es sehr rutschig und belastet die Aufmerksamkeit und Erfahrung des Entwicklers zu sehr.

Die Frage der SQL-Injection kann nicht auf ein bestimmtes Syntaxproblem vereinfacht werden. Es ist breiter als der durchschnittliche Entwickler gedacht. Es ist auch eine methodische Frage. Es ist nicht nur "Welche bestimmte Formatierung müssen wir anwenden", sondern auch " Wie es gemacht werden muss".

(Unter diesem Gesichtspunkt ist ein Artikel von Jon Skeet, der in der anderen Antwort zitiert wird, eher schlecht als gut, da er sich wieder auf einen Randfall konzentriert, sich auf ein bestimmtes Syntaxproblem konzentriert und das Problem überhaupt nicht anspricht.)

Wenn Sie versuchen, die Frage des Schutzes nicht als Ganzes, sondern als eine Reihe verschiedener Syntaxprobleme zu behandeln, stehen Sie vor einer Vielzahl von Problemen.

  • Die Liste der möglichen Formatierungsoptionen ist wirklich riesig. Mittel, die man leicht übersehen kann. Oder verwirren Sie sie (indem Sie beispielsweise eine Zeichenfolge verwenden , die als Kennung dient ).
  • Verkettung bedeutet, dass alle Schutzmaßnahmen vom Programmierer und nicht vom Programmierer durchgeführt werden müssen. Dieses Problem allein führt zu mehreren Konsequenzen:
    • Eine solche Formatierung erfolgt manuell. Manuell bedeutet extrem fehleranfällig. Man könnte einfach vergessen, sich zu bewerben.
    • Darüber hinaus besteht die Versuchung, Formatierungsverfahren in eine zentralisierte Funktion zu verschieben, die Dinge noch mehr durcheinander zu bringen und Daten zu verderben, die nicht in die Datenbank gelangen.
  • Wenn mehr als ein Entwickler beteiligt ist, multiplizieren sich die Probleme mit dem Faktor zehn.
  • Wenn Verkettung verwendet wird, kann man eine potenziell gefährliche Abfrage nicht auf einen Blick erkennen: Sie alle sind potenziell gefährlich!

Im Gegensatz zu diesem Durcheinander sind vorbereitete Aussagen in der Tat der Heilige Gral:

  • Es kann in Form einer einfachen Regel ausgedrückt werden, die leicht zu befolgen ist.
  • Es ist im Wesentlichen eine untrennbare Maßnahme, dh der Entwickler kann sich nicht einmischen und den Prozess freiwillig oder unfreiwillig verderben.
  • Der Schutz vor Injektion ist eigentlich nur ein Nebeneffekt der vorbereiteten Aussagen, deren eigentlicher Zweck darin besteht, syntaktisch korrekte Aussagen zu erstellen. Und eine syntaktisch korrekte Aussage ist 100% injektionssicher. Trotzdem muss unsere Syntax trotz aller Injektionsmöglichkeiten korrekt sein.
  • Wenn es rundum verwendet wird, schützt es die Anwendung unabhängig von der Erfahrung des Entwicklers. Angenommen, es gibt eine Sache, die als Injektion zweiter Ordnung bezeichnet wird . Und eine sehr starke Täuschung, die lautet: "Um alle vom Benutzer bereitgestellten Eingaben zu schützen, entkommen Sie ". Zusammen führen sie zur Injektion, wenn sich ein Entwickler die Freiheit nimmt, zu entscheiden, was geschützt werden muss und was nicht.

(Als ich weiter nachdachte, stellte ich fest, dass der aktuelle Satz von Platzhaltern nicht für die Anforderungen des realen Lebens ausreicht und erweitert werden muss, sowohl für die komplexen Datenstrukturen wie Arrays als auch für SQL-Schlüsselwörter oder -Kennungen, die manchmal zu den hinzugefügt werden müssen Abfrage auch dynamisch, aber ein Entwickler bleibt für einen solchen Fall unbewaffnet und muss auf die Verkettung von Zeichenfolgen zurückgreifen, aber das ist eine andere Frage.

Interessanterweise wird die Kontroverse dieser Frage durch die sehr kontroverse Natur des Stapelüberlaufs provoziert. Die Idee der Website besteht darin, bestimmte Fragen von Benutzern zu verwenden, die direkt nachfragen , um das Ziel einer Datenbank mit allgemeinen Antworten zu erreichen, die für Benutzer geeignet sind, die aus der Suche stammen . Die Idee ist nicht schlecht , per se , aber es funktioniert nicht in einer Situation wie dieser: wenn ein Benutzer eine fragt sehr engen Frage , vor allem in einem Streit um ein Argument zu bekommen mit einem Kollegen (oder zu entscheiden , ob es sich lohnt , den Code zu Refactoring). Während die meisten erfahrenen Teilnehmer versuchen, eine Antwort zu schreiben, denken Sie an die Mission of Stack Overflow insgesamt, was ihre Antwort für so viele Leser wie möglich gut macht, nicht nur für das OP.

Ihr gesunder Menschenverstand
quelle
10
Die Frage nicht beantworten
edc65
Die meisten Datenbanken erkennen bereits verwendete, parametrisierte Abfragen anhand der SQL-Zeichenfolgengleichheit, sodass die alte Methode zur Vorbereitung und Verwendung des Handles für mich veraltet zu sein scheint. Diese Griffe können nur innerhalb eines bestimmten Bereichs verwendet werden und erfordern eine Codierung, um den Griff zu verfolgen. Parametrisierte Abfragen sollten meiner Meinung nach direkt verwendet werden, damit Abfragepläne ohne Handle-Tracking und sogar für verschiedene Anwendungen wiederverwendet werden können.
Erik Hart
15

Denken wir nicht nur an Sicherheitsaspekte oder typsichere Überlegungen.

Der Grund, warum Sie parametrisierte Abfragen verwenden, besteht darin, die Leistung auf Datenbankebene zu verbessern. Aus Datenbanksicht ist eine parametrisierte Abfrage eine Abfrage im SQL-Puffer (um die Terminologie von Oracle zu verwenden, obwohl ich mir vorstelle, dass alle Datenbanken intern ein ähnliches Konzept haben). Die Datenbank kann also eine bestimmte Anzahl von Abfragen im Speicher speichern, die vorbereitet und zur Ausführung bereit sind. Diese Abfragen müssen nicht analysiert werden und sind schneller. Häufig ausgeführte Abfragen befinden sich normalerweise im Puffer und müssen nicht jedes Mal analysiert werden, wenn sie verwendet werden.

ES SEI DENN

Jemand verwendet keine parametrisierten Abfragen. In diesem Fall wird der Puffer kontinuierlich durch einen Strom nahezu identischer Abfragen geleert, von denen jede analysiert und von der Datenbank-Engine ausgeführt werden muss. Die Leistung leidet insgesamt, da selbst häufig ausgeführte Abfragen häufig mehrmals analysiert werden Tag. Ich habe Datenbanken für meinen Lebensunterhalt optimiert und dies war eine der größten Quellen für niedrig hängende Früchte.

JETZT

Um Ihre Frage zu beantworten: Wenn Ihre Abfrage eine kleine Anzahl unterschiedlicher numerischer Werte aufweist, verursachen Sie wahrscheinlich keine Probleme und können die Leistung tatsächlich unendlich verbessern. Wenn jedoch möglicherweise Hunderte von Werten vorhanden sind und die Abfrage häufig aufgerufen wird, wirkt sich dies auf die Leistung Ihres Systems aus. Tun Sie dies also nicht.

Ja, Sie können den SQL-Puffer erhöhen, aber dies geht letztendlich immer zu Lasten anderer kritischerer Speicheranwendungen wie dem Zwischenspeichern von Indizes oder Daten. Moralisch, verwenden Sie parametrisierte Abfragen ziemlich religiös, damit Sie Ihre Datenbank optimieren und mehr Serverspeicher für die wichtigen Dinge verwenden können ...

mcottle
quelle
8

So fügen Sie der Maciek-Antwort einige Informationen hinzu:

Es ist einfach, die Kulturinformationen einer .NET-Drittanbieter-App zu ändern, indem Sie die Hauptfunktion der Assembly durch Reflektion aufrufen:

using System;
using System.Globalization;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      Assembly asm = Assembly.LoadFile(@"C:\BobbysApp.exe");
      MethodInfo mi = asm.GetType("Test").GetMethod("Main");
      mi.Invoke(null, null);
      Console.ReadLine();
    }

    static Program()
    {
      InstallBobbyTablesCulture();
    }

    static void InstallBobbyTablesCulture()
    {
      CultureInfo bobby = (CultureInfo)CultureInfo.InvariantCulture.Clone();
      bobby.DateTimeFormat.ShortDatePattern = @"yyyy-MM-dd'' OR ' '=''";
      bobby.DateTimeFormat.LongTimePattern = "";
      bobby.NumberFormat.NegativeSign = "1 OR 1=1 OR 1=";
      Thread.CurrentThread.CurrentCulture = bobby;
    }
  }
}

Dies funktioniert nur, wenn die Hauptfunktion von BobbysApp öffentlich ist. Wenn Main nicht öffentlich ist, können Sie andere öffentliche Funktionen aufrufen.

user1027167
quelle
1
Sie müssen es nicht einmal per Code tun. Sie können die Injektion direkt in den regionalen Windows-Einstellungen hinzufügen. Siehe meine Antwort.
Kaspars Ozols
2
Wer kann die Servereinstellungen ändern oder wer kann solchen Code im Server reiben? Wenn eine Person dies auf Ihrem Server tun kann, benötigt sie SQL Injection nicht, um Daten zu zerstören.
Reza Aghaei
7

Wenn Sie meiner Meinung nach garantieren können, dass der Parameter, mit dem Sie arbeiten, niemals eine Zeichenfolge enthält, ist dies sicher, aber ich würde es auf keinen Fall tun. Außerdem wird ein leichter Leistungsabfall festgestellt, da Sie eine Verkettung durchführen. Die Frage, die ich Ihnen stellen würde, ist, warum Sie keine Parameter verwenden möchten.

Max
quelle
1
Es ist nicht so, dass ich keine Parameter verwenden möchte, ich verwende Parameter. Ein Mitarbeiter hat Code wie diesen geschrieben, den ich geändert habe, um ihn heute zu parametrisieren, was mich an die Frage denken ließ.
Johnny Rose
OK. Toll. Es wird empfohlen, Parameter zu verwenden. Auf diese Weise müssen Sie sich nicht um Dinge wie SQL-Injection kümmern. Wenn Sie dynamische Abfragen erstellen, können Sie auch Parameter verwenden, unabhängig davon, wie komplex Ihre Abfragen sind. Verwenden Sie beim Erstellen einfach den Stil @ 1 ... @ n. Und hängen Sie sie mit dem gewünschten Wert an die Parametersammlung an.
Max
@johnyRose Es gibt noch einen weiteren Punkt, um Parameter zu verwenden: Programme entwickeln sich und ändern sich. Sie können die Verkettung nur für Zeichenfolgen verwenden, dies garantiert jedoch nicht, dass jemand Refactoring implementiert, das einen Parametertyp ändert, und dass Änderungen zu einer SQL Injection-Sicherheitsanfälligkeit führen können.
Lerthe61
3

Es ist in Ordnung, aber niemals sicher. Und die Sicherheit hängt immer von den Eingaben ab. Wenn das Eingabeobjekt beispielsweise TextBox ist, können die Angreifer etwas Kniffliges tun, da das Textfeld Zeichenfolgen akzeptieren kann. Sie müssen also eine Art Validierung / Konvertierung durchführen um verhindern zu können, dass Benutzer falsche Eingaben machen. Aber die Sache ist, es ist nicht sicher. So einfach ist das.

japzdivino
quelle
Das ist allerdings eine Saite. Ich spreche von anderen Datentypen wie Ganzzahlen, Booleschen Werten oder Datumsangaben.
Johnny Rose
@johnnyRose Yup, ich habe oben ein sehr schönes Beispiel gesehen, das Sie als von Kaspards beantwortet markieren. Und eine großartige Antwort, da er den Datetime-Datentyp als ungewöhnliches Beispiel verwendet. :) Ich hoffe, Sie haben bereits überzeugt, dass es nicht sicher und besser ist, Parameter in Datentypen zu verwenden
japzdivino
Ich hatte nie wirklich Zweifel, dass es sicherer ist, Parameter zu verwenden. Meine Frage bezog sich auf stark typisierte Implementierungen.
Johnny Rose
Ja, ich stimme zu. und das ist auch eine gute Frage, die zukünftigen Lesern helfen kann :)
japzdivino
-2

Nein, auf diese Weise können Sie einen SQL-Injection-Angriff erhalten. Ich habe einen alten Artikel auf Türkisch geschrieben, der zeigt, wie hier . Artikelbeispiel in PHP und MySQL, aber das Konzept funktioniert in C # und SQL Server gleich.

Grundsätzlich greift man folgendermaßen an. Nehmen wir an, Sie haben eine Seite, auf der Informationen nach dem Wert der Ganzzahl-ID angezeigt werden. Sie haben diesen Wert nicht wie unten angegeben parametrisiert.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=24

Okay, ich gehe davon aus, dass Sie MySQL verwenden und ich greife folgendermaßen an.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII((SELECT%20DATABASE()))

Beachten Sie, dass der hier injizierte Wert keine Zeichenfolge ist. Wir ändern den Zeichenwert mithilfe der ASCII-Funktion in int. Sie können dasselbe in SQL Server mit "CAST (YourVarcharCol AS INT)" erreichen.

Danach benutze ich Längen- und Teilzeichenfolgenfunktionen, um nach Ihrem Datenbanknamen zu suchen.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=LEN((SELECT%20DATABASE()))

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR(SELECT%20DATABASE(),1,1))

Wenn Sie dann den Datenbanknamen verwenden, beginnen Sie, Tabellennamen in der Datenbank abzurufen.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR((SELECT table_name FROM INFORMATION_SCHEMA.TABLES LIMIT 1),1,1))

Natürlich müssen Sie diesen Prozess automatisieren, da Sie nur EIN Zeichen pro Abfrage erhalten. Sie können es jedoch problemlos automatisieren. Mein Artikel zeigt ein Beispiel in Watir . Verwenden Sie nur eine Seite und keinen parametrisierten ID-Wert. Ich kann jeden Tabellennamen in Ihrer Datenbank lernen. Danach kann ich nach wichtigen Tabellen suchen. Es wird einige Zeit dauern, aber es ist machbar.

Atilla Ozgur
quelle
2
Meine Frage bezieht sich auf eine stark typisierte Sprache. Während Ihre Erklärung für Sprachen mit flexibler Eingabe großartig ist, ist der injizierte Wert immer noch eine Zeichenfolge.
Johnny Rose
Kein injizierter Wert ist eine Ganzzahl. Sie erhalten char und ändern es mit der ASCII MySQL-Funktion in eine Ganzzahl. Sie tun dasselbe in SQL Server mit CAST (YourCharValue AS INT)
Atilla Ozgur
Ich meinte so etwas:public void QuerySomething(int id) { // this will only accept an integer }
Johnny Rose
-3

Nun ... eines ist sicher: Sicherheit ist NICHT in Ordnung, wenn Sie eine (vom Benutzer verwendete) Zeichenfolge mit Ihrer SQL-Befehlszeichenfolge verketten. Es spielt keine Rolle, wann immer die where-Klausel auf eine Ganzzahl oder einen beliebigen Typ verweist. Injektionen können auftreten.

Was bei SQL Injection wichtig ist, ist der Datentyp der Variablen, mit der der Wert vom Benutzer abgerufen wurde.

Angenommen, wir haben eine Ganzzahl in der where-Klausel und:

  1. Die Benutzervariable ist eine Zeichenfolge. Dann ok, es ist nicht sehr einfach zu injizieren (mit UNION), aber es ist sehr einfach, mit 'OR 1 = 1' zu umgehen - wie Angriffe ...

  2. Wenn die Benutzervariable eine Ganzzahl ist. Andererseits können wir die Stärke des Systems "testen", indem wir ungewöhnlich große Zahlen auf Systemabstürze oder sogar auf einen versteckten Pufferüberlauf (auf der letzten Zeichenfolge) testen ...;)

Möglicherweise sind die Parameter für Abfragen oder (noch besser - imo) für gespeicherte Prozeduren nicht 100% sicher, aber sie sind die am wenigsten erforderliche Maßnahme (oder die elementare, wenn Sie dies bevorzugen), um sie zu minimieren.

Andreas Venieris
quelle
Ich denke, Sie haben die Frage vielleicht falsch verstanden. Ich spreche von Nicht- String-Typen.
Johnny Rose
Hallo JonnyRose ... danke für deinen Hinweis. Ich verstehe Ihre Frage, aber ich habe meine Antwort nur allgemeiner formuliert. Für Fälle ohne Zeichenfolge überprüfen Sie bitte meinen (2) Punkt. ;)
Andreas Venieris