Vermeiden der SQL-Injection ohne Parameter


109

Wir haben hier eine weitere Diskussion über die Verwendung parametrisierter SQL-Abfragen in unserem Code. Wir haben zwei Seiten in der Diskussion: Ich und einige andere, die sagen, wir sollten immer Parameter verwenden, um uns vor SQL-Injektionen zu schützen, und die anderen, die es nicht für notwendig halten. Stattdessen möchten sie einzelne Apostrophe durch zwei Apostrophe in allen Zeichenfolgen ersetzen, um SQL-Injektionen zu vermeiden. Auf unseren Datenbanken wird Sql Server 2005 oder 2008 ausgeführt, und auf unserer Codebasis wird .NET Framework 2.0 ausgeführt.

Lassen Sie mich Ihnen ein einfaches Beispiel in C # geben:

Ich möchte, dass wir dies verwenden:

string sql = "SELECT * FROM Users WHERE Name=@name";
SqlCommand getUser = new SqlCommand(sql, connection);
getUser.Parameters.AddWithValue("@name", userName);
//... blabla - do something here, this is safe

Während die anderen das machen wollen:

string sql = "SELECT * FROM Users WHERE Name=" + SafeDBString(name);
SqlCommand getUser = new SqlCommand(sql, connection);
//... blabla - are we safe now?

Wo die SafeDBString-Funktion wie folgt definiert ist:

string SafeDBString(string inputValue) 
{
    return "'" + inputValue.Replace("'", "''") + "'";
}

Solange wir SafeDBString für alle Zeichenfolgenwerte in unseren Abfragen verwenden, sollten wir jetzt sicher sein. Richtig?

Es gibt zwei Gründe, die SafeDBString-Funktion zu verwenden. Erstens ist es so, wie es seit der Steinzeit gemacht wurde, und zweitens ist es einfacher, die SQL-Anweisungen zu debuggen, da Sie die exakte Abfrage sehen, die in der Datenbank ausgeführt wird.

Also dann. Meine Frage ist, ob es wirklich ausreicht, die SafeDBString-Funktion zu verwenden, um SQL-Injection-Angriffe zu vermeiden. Ich habe versucht, Beispiele für Code zu finden, der diese Sicherheitsmaßnahme verletzt, aber ich kann keine Beispiele dafür finden.

Gibt es da draußen jemanden, der das brechen kann? Wie würdest du es machen?

EDIT: Um die bisherigen Antworten zusammenzufassen:

  • Bisher hat noch niemand einen Weg gefunden, um SafeDBString auf SQL Server 2005 oder 2008 zu umgehen. Das ist gut, denke ich?
  • In mehreren Antworten wurde darauf hingewiesen, dass Sie bei Verwendung parametrisierter Abfragen einen Leistungsgewinn erzielen. Der Grund ist, dass die Abfragepläne wiederverwendet werden können.
  • Wir sind uns auch einig, dass die Verwendung parametrisierter Abfragen besser lesbaren Code liefert, der einfacher zu warten ist
  • Außerdem ist es einfacher, immer Parameter zu verwenden, als verschiedene Versionen von SafeDBString, Konvertierungen von Zeichenfolgen in Zahlen und Konvertierungen von Zeichenfolgen in Datumsangaben zu verwenden.
  • Wenn Sie Parameter verwenden, erhalten Sie eine automatische Typkonvertierung. Dies ist besonders nützlich, wenn Sie mit Datums- oder Dezimalzahlen arbeiten.
  • Und schließlich: Versuchen Sie nicht, selbst Sicherheit zu leisten, wie JulianR schrieb. Die Datenbankanbieter investieren viel Zeit und Geld in die Sicherheit. Es gibt keine Möglichkeit, es besser zu machen, und keinen Grund, warum wir versuchen sollten, ihre Arbeit zu erledigen.

Obwohl niemand in der Lage war, die einfache Sicherheit der SafeDBString-Funktion zu beeinträchtigen, habe ich viele andere gute Argumente erhalten. Vielen Dank!


16
Ihre Kollegen sind weit weg von der Basis. Fordern Sie sie auf, ein einziges Stück Literatur zur Unterstützung ihrer Position zu finden. Das Argument ex neolithos ist lächerlich, Dinge ändern sich, nur eine Person, die in der Steinzeit steckt, würde sich nicht anpassen können.
Annakata

1
Nun, zumindest schützen Ihre Kollegen vor EINER der verschiedenen Formen von Hack ... Sind sie sicher, dass alle parametrisierten Abfragen dies tun? (Ich bin nicht ...)
Arjan Einbu

1
Eine Schwachstelle wird sie nicht überzeugen. Wenn Sie mehrere Schwachstellen (nach denen Sie fragen) und andere Probleme mitbringen und nacheinander darauf hinweisen, dass Parameter dieses Problem lösen und Ihr Team Berge von Code schreiben müsste, um einen Bruchteil der Funktionalität bereitzustellen, können Sie dies tun Gewinnen Sie sie. Viel Glück.
Robert Gowland

3
Auch ohne einfache Anführungszeichen können Sie Ihren Code mit Logik brechen. Versuchen Sie es mit dem Benutzernamen "test OR 1 = 1" - Sie erhalten alle Zeilen zurück und nicht nur die mit dem Benutzernamen test!
Brücke

1
Seufzer. Ich verstehe wirklich nicht, wie wir als Branche es schaffen, diese Art von unprofessionellem Verhalten weiterhin zu tolerieren.
Jeroenh

Antworten:


83

Ich denke die richtige Antwort ist:

Versuchen Sie nicht, selbst Sicherheit zu leisten . Verwenden Sie eine beliebige vertrauenswürdige Bibliothek nach Industriestandard, die für das verfügbar ist, was Sie tun möchten, anstatt es zu versuchen es selbst zu . Unabhängig davon, welche Annahmen Sie zur Sicherheit treffen, sind diese möglicherweise falsch. So sicher Ihr eigener Ansatz auch aussehen mag (und er sieht bestenfalls wackelig aus), es besteht das Risiko, dass Sie etwas übersehen, und möchten Sie diese Chance wirklich nutzen, wenn es um Sicherheit geht?

Verwenden Sie Parameter.


Betreff "Verwenden Sie eine vertrauenswürdige Bibliothek nach Industriestandard" - können Sie eine für .NET empfehlen? Je nach Datenbank möglicherweise mehr als eine: SQLServer, MySQL, PostgreSQL? Ich habe nach SQL-Desinfektionsmitteln gesucht, aber ohne viel Glück, also war ich gezwungen, meine eigenen zu implementieren, so gut ich kann (was zweifellos alles andere als narrensicher ist).
Netzteil

72

Und dann geht jemand und verwendet "statt". Parameter sind, IMO, der einzig sichere Weg.

Es vermeidet auch viele i18n-Probleme mit Datums- / Zahlenangaben. Welches Datum ist der 01.02.03? Wie viel ist 123.456? Stimmen Ihre Server (App-Server und DB-Server) überein?

Wenn der Risikofaktor sie nicht überzeugt, wie steht es dann mit der Leistung? Das RDBMS kann den Abfrageplan wiederverwenden, wenn Sie Parameter verwenden, um die Leistung zu verbessern. Dies kann nicht nur mit der Zeichenfolge geschehen.


Ich habe die Formatierungs- und Leistungsargumente ausprobiert, aber sie sind immer noch nicht überzeugt.
Rune Grimstad

5
Tatsächlich kann der SQL Server den Abfrageplan wiederverwenden, unabhängig davon, ob Sie Parameter verwenden oder nicht. Ich stimme den anderen Argumenten zu, aber in den meisten Fällen fliegt das Leistungsargument für parametrisiertes SQL nicht mehr.
tnyfst

1
@tnyfst: Kann der Ausführungsplan wiederverwendet werden, wenn sich die Abfragezeichenfolge für jede Kombination von Parameterwerten ändert? Ich hielt das nicht für möglich.
John Saunders

4
Der Abfrageplan wird wiederverwendet, wenn der Abfragetext IDENTISCH zu einem früheren Abfragetext ist. Wenn Sie also die EXACT SAME-Abfrage zweimal senden, wird sie wiederverwendet. Wenn Sie jedoch nur ein Leerzeichen, ein Komma oder etwas anderes ändern, muss ein neuer Abfrageplan festgelegt werden.
marc_s

1
@Marc: Ich bin nicht sicher, ob Sie ganz richtig sind. SQL Server-Caching-Hueristiken sind etwas seltsam. Der Parser kann Konstanten im Text identifizieren und die SQL-Zeichenfolge in eine Zeichenfolge konvertieren, die künstlich verwendet wird. Anschließend kann der Text dieser neuen parametrisierten Abfrage in den Cache eingefügt werden. Nachfolgende ähnliche SQL-Dateien finden möglicherweise ihre übereinstimmende parametrisierte Version im Cache. Parametrisierte Versionen werden jedoch nicht immer verwendet, wenn stattdessen die ursprünglichen SQL-Versionen zwischengespeichert werden. Ich vermute, dass SQL zig leistungsbedingte Gründe hat, zwischen den beiden Ansätzen zu wählen.
AnthonyWJones

27

Das Argument ist ein No-Win. Wenn es Ihnen gelingt, eine Sicherheitsanfälligkeit zu finden, ändern Ihre Mitarbeiter lediglich die SafeDBString-Funktion, um dies zu berücksichtigen, und bitten Sie dann, erneut zu beweisen, dass sie unsicher ist.

Angesichts der Tatsache, dass parametrisierte Abfragen eine unbestrittene bewährte Programmiermethode sind, sollte die Beweislast bei ihnen liegen, um anzugeben, warum sie keine Methode verwenden, die sowohl sicherer als auch leistungsfähiger ist.

Wenn das Problem darin besteht, den gesamten Legacy-Code neu zu schreiben, besteht der einfache Kompromiss darin, parametrisierte Abfragen in allen neuen Codes zu verwenden und alten Code zu überarbeiten, um sie bei der Arbeit an diesem Code zu verwenden.

Ich vermute, das eigentliche Problem ist Stolz und Sturheit, und Sie können nicht viel mehr dagegen tun.


19

Zunächst ist Ihr Beispiel für die "Ersetzen" -Version falsch. Sie müssen Apostrophe um den Text setzen:

string sql = "SELECT * FROM Users WHERE Name='" + SafeDBString(name) & "'";
SqlCommand getUser = new SqlCommand(sql, connection);

Das ist eine weitere Sache, die Parameter für Sie tun: Sie müssen sich keine Gedanken darüber machen, ob ein Wert in Anführungszeichen gesetzt werden muss oder nicht. Natürlich können Sie das in die Funktion einbauen, aber dann müssen Sie der Funktion eine Menge Komplexität hinzufügen: Wie erkennt man den Unterschied zwischen 'NULL' als Null und 'NULL' nur als Zeichenfolge oder zwischen einer Zahl und Eine Zeichenfolge, die zufällig viele Ziffern enthält. Es ist nur eine weitere Quelle für Fehler.

Eine andere Sache ist die Leistung: Parametrisierte Abfragepläne werden häufig besser zwischengespeichert als verkettete Pläne, wodurch der Server möglicherweise einen Schritt beim Ausführen der Abfrage spart.

Darüber hinaus ist es nicht gut genug, einfachen Anführungszeichen zu entkommen. Viele DB-Produkte ermöglichen alternative Methoden zum Entkommen von Charakteren, die ein Angreifer nutzen könnte. In MySQL können Sie beispielsweise auch ein einfaches Anführungszeichen mit einem Backslash umgehen. Und so würde der folgende "Name" -Wert MySQL nur mit der SafeDBString()Funktion in die Luft jagen , denn wenn Sie das einfache Anführungszeichen verdoppeln, wird das erste immer noch durch den Backslash maskiert, so dass das zweite "aktiv" bleibt:

x \ 'OR 1 = 1; -


Außerdem bringt julianr einen guten Punkt unten nach oben: NIEMALS versuchen , die Sicherheit der Arbeit selbst zu tun. Es ist so einfach Sicherheit Programmierung falsch auf subtile Weise zu erhalten, erscheinen zu machen, die selbst bei gründlichen Tests zu funktionieren . Dann vergeht die Zeit und ein Jahr später haben Sie herausgefunden, dass Ihr System vor sechs Monaten geknackt wurde und Sie haben es bis dahin noch nicht einmal gewusst.

Verlassen Sie sich immer so weit wie möglich auf die für Ihre Plattform bereitgestellten Sicherheitsbibliotheken. Sie werden von Personen geschrieben, die ihren Lebensunterhalt mit Sicherheitscodes verdienen, viel besser getestet als das, was Sie verwalten können, und vom Anbieter gewartet, wenn eine Sicherheitslücke gefunden wird.


5
Die Ersetzungsfunktion fügt die Apostrophe hinzu
Rune Grimstad

5
Dann ist es nur noch eine Fehlerquelle. Woher kennt es den Unterschied zwischen NULL als Nullwert und NULL als Textzeichenfolge? Oder zwischen einer Zahleneingabe und einer Zeichenfolge, die zufällig Ziffern enthält?
Joel Coehoorn

Guter Punkt. Sie sollten die Funktion nur für Zeichenfolgen und möglicherweise Datumsangaben verwenden, daher müssen Sie vorsichtig sein. Das ist ein Grund mehr, Parameter zu verwenden! Yay!
Rune Grimstad

10

Also würde ich sagen:

1) Warum versuchen Sie, etwas, das eingebaut ist, erneut zu implementieren? Es ist da, leicht verfügbar, einfach zu bedienen und bereits weltweit getestet. Wenn zukünftige Fehler darin gefunden werden, werden sie behoben und stehen allen sehr schnell zur Verfügung, ohne dass Sie etwas tun müssen.

2) Welche Prozesse sind vorhanden, um sicherzustellen, dass Sie nie einen Anruf zu SafeDBString verpassen? Das Fehlen an nur einer Stelle könnte eine ganze Reihe von Problemen aufwerfen. Wie viel werden Sie diese Dinge in Augenschein nehmen und überlegen, wie viel Verschwendung diese Mühe ist, wenn die akzeptierte richtige Antwort so leicht zu erreichen ist.

3) Wie sicher sind Sie, dass Sie jeden Angriffsvektor abgedeckt haben, den Microsoft (der Autor der Datenbank und der Zugriffsbibliothek) in Ihrer SafeDBString-Implementierung kennt ...

4) Wie einfach ist es, die Struktur des SQL zu lesen? Das Beispiel verwendet + Verkettung, Parameter sind sehr ähnlich wie string.Format, das besser lesbar ist.

Es gibt auch zwei Möglichkeiten, um herauszufinden, was tatsächlich ausgeführt wurde: Rollen Sie Ihre eigene LogCommand-Funktion, eine einfache Funktion ohne Sicherheitsbedenken , oder sehen Sie sich sogar eine SQL-Ablaufverfolgung an, um herauszufinden, was die Datenbank wirklich vorhat.

Unsere LogCommand-Funktion lautet einfach:

    string LogCommand(SqlCommand cmd)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(cmd.CommandText);
        foreach (SqlParameter param in cmd.Parameters)
        {
            sb.Append(param.ToString());
            sb.Append(" = \"");
            sb.Append(param.Value.ToString());
            sb.AppendLine("\"");
        }
        return sb.ToString();
    }

Richtig oder falsch, es gibt uns die Informationen, die wir ohne Sicherheitsprobleme benötigen.


1
Er muss sich wahrscheinlich mit einigen alten VBSCRIPT-Programmierern auseinandersetzen, die es gewohnt sind, alles, einschließlich XML und SQL, durch Verkettung von Zeichenfolgen zu erledigen. Dies sind Menschen, die Angst vor der Verwendung einer API haben. Mit ihnen kann nicht viel getan werden, zumindest nichts Menschliches.
John Saunders

1
+1 für Punkt 2, mit der Ausnahme, dass es auch keine Möglichkeit gibt, echte Parameter durchzusetzen.
Joel Coehoorn

7

Mit parametrisierten Abfragen erhalten Sie mehr als nur Schutz vor SQL-Injection. Sie erhalten auch ein besseres Caching-Potenzial für Ausführungspläne. Wenn Sie den SQL Server-Abfrageprofiler verwenden, sehen Sie immer noch die "genaue SQL, die in der Datenbank ausgeführt wird", sodass Sie auch beim Debuggen Ihrer SQL-Anweisungen nichts wirklich verlieren.


MySQL protokolliert auch parametrisierte Abfragen mit darin interpolierten Parameterwerten.
Bill Karwin

5

Ich habe beide Ansätze verwendet, um SQL-Injection-Angriffe zu vermeiden, und bevorzuge definitiv parametrisierte Abfragen. Wenn ich verkettete Abfragen verwendet habe, habe ich eine Bibliotheksfunktion verwendet, um den Variablen zu entkommen (wie mysql_real_escape_string), und wäre nicht sicher, ob ich alles in einer proprietären Implementierung behandelt habe (wie es scheint, sind Sie es auch).


2
+1, weil mysql_real_escape_string () \ x00, \ x1a, \ n \ r 'und "entgeht. Es behandelt auch Probleme mit Zeichensätzen. Die naive Funktion der OP-Mitarbeiter macht nichts davon!
Bill Karwin

4

Ohne die Verwendung von Parametern können Sie die Benutzereingaben nicht einfach überprüfen.

Wenn Sie die Klassen SQLCommand und SQLParameter verwenden, um DB-Aufrufe auszuführen, wird die ausgeführte SQL-Abfrage weiterhin angezeigt. Sehen Sie sich die CommandText-Eigenschaft von SQLCommand an.

Ich bin immer ein kleiner Verdächtiger des Roll-Your-Own-Ansatzes zur Verhinderung der SQL-Injection, wenn parametrisierte Abfragen so einfach zu verwenden sind. Zweitens, nur weil "es immer so gemacht wurde", heißt das nicht, dass es der richtige Weg ist.


3

Dies ist nur dann sicher, wenn Sie garantiert sind, dass Sie eine Zeichenfolge übergeben.

Was ist, wenn Sie irgendwann keine Zeichenfolge mehr eingeben? Was ist, wenn Sie nur eine Nummer übergeben?

http://www.mywebsite.com/profile/?id=7;DROP DATABASE DB

Würde letztendlich werden:

SELECT * FROM DB WHERE Id = 7;DROP DATABASE DB

Es ist entweder eine Zeichenfolge oder eine Zahl. Eine Zeichenfolge wird mit SafeDbString maskiert. Eine Nummer ist eine Int32 und kann keine Datenbanken löschen.
Andomar

Zahlen sind einfacher zu handhaben. Sie konvertieren den Parameter einfach in ein int / float / Whatever, bevor Sie ihn in der Abfrage verwenden. Das Problem ist, wenn Sie Zeichenfolgendaten akzeptieren müssen.
Rune Grimstad

Andomar - Wenn Sie nur eine SQL-Anweisung von Hand erstellen, spielt der beabsichtigte "Typ" keine Rolle. Sie können SQL sehr, sehr einfach mit einer Zahl injizieren. Rune - Ich denke, dies hängt viel zu sehr vom einzelnen Entwickler ab, um sich an alle Nuancen der manuellen Lösung der SQL-Injection zu erinnern. Wenn Sie nur "Parameter verwenden" sagen, ist dies sehr einfach und sie können nichts falsch machen.
Joshcomley

@Andomar: Was ist mit NULL? Oder Zeichenfolgen, die wie Zahlen aussehen?
Joel Coehoorn

2

Ich würde gespeicherte Prozeduren oder Funktionen für alles verwenden, damit sich die Frage nicht stellt.

Wo ich SQL in Code einfügen muss, verwende ich Parameter, was das einzige ist, was Sinn macht. Erinnern Sie die Andersdenkenden daran, dass es Hacker gibt, die schlauer sind als sie, und mit einem besseren Anreiz, den Code zu brechen, der versucht, sie zu überlisten. Mit Parametern ist das einfach nicht möglich und es ist auch nicht schwierig.


Ok, wie mache ich eine SQL-Injection mit Parametern?
John Saunders

@Saunders: Schritt 1 besteht darin, einen Pufferüberlauffehler in der Parameterbehandlungsfunktion Ihrer Datenbank zu finden.
Brian

2
Schon einen gefunden? In einer kommerziellen DB, die täglich von Hunderttausenden von Hackern angegriffen wird? Eine von einem Softwareunternehmen, das bekanntermaßen sehr tiefe Taschen hat? Wenn dies möglich wäre, könnten Sie die Klage namentlich zitieren .
John Saunders

1
Wenn der SPROC Verkettung und EXEC (anstelle von sp_ExecuteSQL) verwendet, sind Sie natürlich wieder in Schwierigkeiten ... (Ich habe gesehen, dass es zu oft falsch gemacht wurde, um es zu reduzieren ...)
Marc Gravell

2

Stimmen Sie den Sicherheitsfragen sehr zu.
Ein weiterer Grund für die Verwendung von Parametern ist die Effizienz.

Datenbanken kompilieren Ihre Abfrage immer und zwischenspeichern sie. Anschließend wird die zwischengespeicherte Abfrage erneut verwendet (was für nachfolgende Anforderungen offensichtlich schneller ist). Wenn Sie Parameter verwenden, verwendet die Datenbank Ihre zwischengespeicherte Abfrage auch dann wieder, wenn sie unterschiedliche Parameter verwendet, basierend auf der SQL-Zeichenfolge, bevor die Parameter gebunden werden.

Wenn Sie jedoch keine Parameter binden, ändert sich die SQL-Zeichenfolge bei jeder Anforderung (die unterschiedliche Parameter hat) und stimmt nie mit dem überein, was sich in Ihrem Cache befindet.


2

Aus den bereits genannten Gründen sind Parameter eine sehr gute Idee. Wir hassen es jedoch, sie zu verwenden, da das Erstellen des Parameters und das Zuweisen seines Namens zu einer Variablen zur späteren Verwendung in einer Abfrage ein dreifaches Kopfwrack der Indirektion ist.

Die folgende Klasse umschließt den Stringbuilder, den Sie normalerweise zum Erstellen von SQL-Anforderungen verwenden. Damit können Sie parametrisierte Abfragen schreiben, ohne jemals einen Parameter erstellen zu müssen , sodass Sie sich auf SQL konzentrieren können. Ihr Code wird so aussehen ...

var bldr = new SqlBuilder( myCommand );
bldr.Append("SELECT * FROM CUSTOMERS WHERE ID = ").Value(myId, SqlDbType.Int);
//or
bldr.Append("SELECT * FROM CUSTOMERS WHERE NAME LIKE ").FuzzyValue(myName, SqlDbType.NVarChar);
myCommand.CommandText = bldr.ToString();

Ich hoffe, Sie stimmen zu, dass die Lesbarkeit des Codes erheblich verbessert wurde und die Ausgabe eine ordnungsgemäß parametrisierte Abfrage ist.

Die Klasse sieht so aus ...

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace myNamespace
{
    /// <summary>
    /// Pour le confort et le bonheur, cette classe remplace StringBuilder pour la construction
    /// des requêtes SQL, avec l'avantage qu'elle gère la création des paramètres via la méthode
    /// Value().
    /// </summary>
    public class SqlBuilder
    {
        private StringBuilder _rq;
        private SqlCommand _cmd;
        private int _seq;
        public SqlBuilder(SqlCommand cmd)
        {
            _rq = new StringBuilder();
            _cmd = cmd;
            _seq = 0;
        }
        //Les autres surcharges de StringBuilder peuvent être implémenté ici de la même façon, au besoin.
        public SqlBuilder Append(String str)
        {
            _rq.Append(str);
            return this;
        }
        /// <summary>
        /// Ajoute une valeur runtime à la requête, via un paramètre.
        /// </summary>
        /// <param name="value">La valeur à renseigner dans la requête</param>
        /// <param name="type">Le DBType à utiliser pour la création du paramètre. Se référer au type de la colonne cible.</param>
        public SqlBuilder Value(Object value, SqlDbType type)
        {
            //get param name
            string paramName = "@SqlBuilderParam" + _seq++;
            //append condition to query
            _rq.Append(paramName);
            _cmd.Parameters.Add(paramName, type).Value = value;
            return this;
        }
        public SqlBuilder FuzzyValue(Object value, SqlDbType type)
        {
            //get param name
            string paramName = "@SqlBuilderParam" + _seq++;
            //append condition to query
            _rq.Append("'%' + " + paramName + " + '%'");
            _cmd.Parameters.Add(paramName, type).Value = value;
            return this; 
        }

        public override string ToString()
        {
            return _rq.ToString();
        }
    }
}

1

Aus der sehr kurzen Zeit, in der ich SQL-Injection-Probleme untersuchen musste, kann ich erkennen, dass das Festlegen eines Werts "sicher" auch bedeutet, dass Sie die Tür zu Situationen schließen, in denen Sie möglicherweise tatsächlich Apostrophe in Ihren Daten haben möchten - was ist mit dem Namen einer Person? zB O'Reilly.

Damit bleiben Parameter und gespeicherte Prozeduren übrig.

Und ja, Sie sollten immer versuchen, Code so zu implementieren, wie Sie es jetzt wissen - nicht nur, wie es immer gemacht wurde.


Die doppelten Apostrophe werden vom SQL Server in einen einzelnen Apostroph übersetzt, sodass O'Reilly
Rune Grimstad übersetzt wird

Gibt es also eine entsprechende Funktion zum Entfernen von Apostrophen, wenn der Benutzer seine Daten sehen möchte?
Quamrana

Das ist nicht nötig. Die Escape-Sequenz ermöglicht es dem Parser, ein einfaches Anführungszeichen anstelle des Endes der Zeichenfolge zu sehen. Beim Parsen wird es ''als Literal angezeigt ', sodass Ihre Zeichenfolge intern als Zeichenfolge angezeigt wird O'Reilly. Das ist es, was die Datenbank speichert, abruft, vergleicht usw. Wenn Sie dem Benutzer seine Daten anzeigen möchten, nachdem Sie ihm entkommen sind, behalten Sie eine Kopie der nicht entkappten Zeichenfolge appside.
CHao

1

Hier sind einige Artikel, die Sie möglicherweise hilfreich finden, um Ihre Mitarbeiter zu überzeugen.

http://www.sommarskog.se/dynamic_sql.html

http://unixwiz.net/techtips/sql-injection.html

Persönlich ziehe ich es vor, niemals zuzulassen, dass dynamischer Code meine Datenbank berührt, sodass alle Kontakte über sps erfolgen müssen (und nicht über dynamische SQl). Dies bedeutet, dass nichts anderes getan werden kann, als was ich den Benutzern erteilt habe, und dass interne Benutzer (mit Ausnahme der wenigen Benutzer mit Produktionszugriff für Verwaltungszwecke) nicht direkt auf meine Tabellen zugreifen und Chaos anrichten, Daten stehlen oder Betrug begehen können. Wenn Sie eine Finanzanwendung ausführen, ist dies der sicherste Weg.


1

Es kann kaputt gehen, die Mittel hängen jedoch von den genauen Versionen / Patches usw. ab.

Einer, der bereits angesprochen wurde, ist der Überlauf- / Kürzungsfehler, der ausgenutzt werden kann.

Ein weiteres zukünftiges Mittel wäre das Auffinden von Fehlern, die anderen Datenbanken ähnlich sind - zum Beispiel hatte der MySQL / PHP-Stack ein Fluchtproblem, weil bestimmte UTF8-Sequenzen zur Manipulation der Ersetzungsfunktion verwendet werden könnten - die Ersetzungsfunktion würde dazu verleitet , die Injektionszeichen einzuführen .

Letztendlich beruht der Ersatzsicherheitsmechanismus auf der erwarteten, aber nicht beabsichtigten Funktionalität. Da die Funktionalität nicht der beabsichtigte Zweck des Codes war, besteht eine hohe Wahrscheinlichkeit, dass eine entdeckte Eigenart Ihre erwartete Funktionalität beeinträchtigt.

Wenn Sie viel Legacy-Code haben, kann die Ersetzungsmethode als Notlösung verwendet werden, um langwieriges Umschreiben und Testen zu vermeiden. Wenn Sie neuen Code schreiben, gibt es keine Entschuldigung.


1

Verwenden Sie nach Möglichkeit immer parametrisierte Abfragen. Manchmal kann sogar eine einfache Eingabe ohne die Verwendung seltsamer Zeichen bereits eine SQL-Injection erstellen, wenn sie nicht als Eingabe für ein Feld in der Datenbank identifiziert wird.

Lassen Sie die Datenbank also einfach die Eingabe selbst identifizieren, ganz zu schweigen davon, dass dies auch viel Ärger erspart, wenn Sie tatsächlich seltsame Zeichen einfügen müssen, die sonst maskiert oder geändert würden. Es kann am Ende sogar wertvolle Laufzeit sparen, wenn die Eingabe nicht berechnet werden muss.


1

Ich habe keine anderen Antwortenden gesehen, die sich mit dieser Seite des "Warum es schlecht ist, es selbst zu tun" befasst haben, aber ich habe einen SQL-Kürzungsangriff in Betracht gezogen .

Es gibt auch die QUOTENAMET-SQL-Funktion, die hilfreich sein kann, wenn Sie sie nicht davon überzeugen können, Parameter zu verwenden. Es fängt eine Menge (alle?) Der entkommenen Qoute-Bedenken auf.


1

2 Jahre später rezidivierte ich ... Jeder, der Parameter als schmerzhaft empfindet, kann meine VS-Erweiterung QueryFirst ausprobieren . Sie bearbeiten Ihre Anfrage in einer echten SQL-Datei (Validation, Intellisense). Um einen Parameter hinzuzufügen, geben Sie ihn einfach direkt in Ihre SQL ein und beginnen mit dem '@'. Wenn Sie die Datei speichern, generiert QueryFirst Wrapper-Klassen, mit denen Sie die Abfrage ausführen und auf die Ergebnisse zugreifen können. Es wird den DB-Typ Ihres Parameters nachschlagen und ihn einem .net-Typ zuordnen, den Sie als Eingabe für die generierten Execute () -Methoden finden.Einfacher geht es nicht . Es richtig zu machen ist radikal schneller und einfacher als es auf andere Weise zu tun, und das Erstellen einer SQL-Injection-Schwachstelle wird unmöglich oder zumindest pervers schwierig. Es gibt noch weitere Vorteile, z. B. das Löschen von Spalten in Ihrer Datenbank und das sofortige Anzeigen von Kompilierungsfehlern in Ihrer Anwendung.

Haftungsausschluss: Ich habe QueryFirst geschrieben


0

Hier einige Gründe für die Verwendung parametrisierter Abfragen:

  1. Sicherheit - Die Datenbankzugriffsschicht kann Elemente entfernen oder maskieren, die in Daten nicht zulässig sind.
  2. Trennung von Bedenken - Mein Code ist nicht dafür verantwortlich, die Daten in ein Format umzuwandeln, das der Datenbank gefällt.
  3. Keine Redundanz - Ich muss nicht in jedes Projekt, das diese Datenbank formatiert / maskiert, eine Assembly oder Klasse einfügen. Es ist in die Klassenbibliothek integriert.

0

Es gab nur wenige Sicherheitslücken (ich kann mich nicht erinnern, um welche Datenbank es sich handelte), die mit dem Pufferüberlauf der SQL-Anweisung zusammenhängen.

Was ich sagen möchte ist, dass SQL-Injection mehr ist als nur "dem Zitat entkommen", und Sie haben keine Ahnung, was als nächstes kommt.


0

Ein weiterer wichtiger Aspekt ist die Verfolgung von entgangenen und nicht entführten Daten. Es gibt Unmengen von Anwendungen, Web und andere, die nicht richtig zu verfolgen scheinen, wenn Daten Roh-Unicode, & -kodiertes, formatiertes HTML usw. sind. Es ist offensichtlich, dass es schwierig wird, zu verfolgen, welche Zeichenfolgen ''codiert sind und welche nicht.

Es ist auch ein Problem, wenn Sie am Ende den Typ einer Variablen ändern - vielleicht war es früher eine Ganzzahl, aber jetzt ist es eine Zeichenfolge. Jetzt hast du ein Problem.

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.