2013-07-07 15 views
6

Ich bin neu bei Asp.net und ich fange gerade an, mit Klassen zu arbeiten. Ich habe vor kurzem eine Klasse erstellt, die die meisten meiner SQL-Abfragen für mich behandelt, so dass ich nicht immer neue Verbindungen über alle meine Dateien erstellen muss.parametrisierte Abfragen vs. SQL-Injektion

Eine der Methoden, die ich erstellt habe, nimmt eine SQL-Abfrage als Parameter und gibt das Ergebnis zurück. Ich weiß, dass ich parametrisierte Abfragen verwenden sollte, um SQL-Injektionen zu vermeiden. Meine Frage ist, wie kann ich dies tun, wenn ich die Abfrage als String-Parameter übergeben?

Zum Beispiel, hier ist eine Methode, die ich nennen werde:

public static DataTable SqlDataTable(string sql) 
{ 
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString)) 
    { 
     SqlCommand cmd = new SqlCommand(sql, conn); 
     cmd.Connection.Open(); 
     DataTable TempTable = new DataTable(); 
     TempTable.Load(cmd.ExecuteReader()); 
     return TempTable; 
    } 
} 

Also aus einer anderen Datei würde Ich mag diese Methode verwenden, etwa so:

DataTable dt = new DataTable(); 

dt = SqlComm.SqlDataTable("SELECT * FROM Users WHERE UserName='" + login.Text + "' and Password='" + password.Text + "'"); 

if (dt.Rows.Count > 0) 
{ 
    // do something if the query returns rows 
} 

Das funktioniert aber trotzdem anfällig für Injektionen richtig? Gibt es eine Möglichkeit, die Variablen als Parameter an die Zeichenkette zu übergeben? Ich weiß, dass ich das tun kann, wenn ich ein neues SQLCommand-Objekt für die Abfrage erzeuge und Parameter.AddWithValue verwende, aber ich möchte, dass alle meine SQL-Befehle in der separaten Klasse sind.

+0

Warum Sie Inline-Abfrage verwenden? Sie können die Speicherprozedur verwenden, um SQL-Injektionen zu vermeiden. Speicherprozedur ist eine zuvor ausgeführte SQL-Abfrage. So wird es schneller als Inline-Abfrage ausgeführt. ich schlage nur vor, die Store-Prozedur zu verwenden. –

+0

Ich war einmal dort, ich *** stark *** Sie vertiefen sich in Lernen und ORM (Ich wählte Entity Framework). Ich habe viele Stunden damit verbracht, Code zu schreiben, nur um herauszufinden, wie unnötig das war! Bevor es zu spät ist, lernen Sie Entity Framework. Wenn Sie nicht zu komplexe Abfragen und vor allem zu einfachen CRUD-Operationen haben, ist es nicht so schwer zu lernen .. –

+0

Hiren, gespeicherte Prozeduren sind keine vor ausgeführten Abfragen .. Meinen Sie den Ausführungsplan? –

Antwort

13

Das funktioniert aber trotzdem zu Injektionen direkt anfällig?

Ja, Ihr Code ist erschreckend anfällig für SQL-Injektionen.

Ich weiß, dass ich parametrisierte Abfragen verwenden sollte, um SQL-Injektionen zu vermeiden.

Oh absolut ja.

Meine Frage ist, wie kann ich dies tun, wenn ich die Abfrage als String-Parameter übergeben?

Sie sollten einfach nicht die Abfrage als String-Parameter übergeben. Stattdessen sollten Sie die Abfrage als String-Parameter enthalten Platzhalter und die Werte für die Platzhalter werden übergeben:

public static DataTable SqlDataTable(string sql, IDictionary<string, object> values) 
{ 
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString)) 
    using (SqlCommand cmd = conn.CreateCommand()) 
    { 
     conn.Open(); 
     cmd.CommandText = sql; 
     foreach (KeyValuePair<string, object> item in values) 
     { 
      cmd.Parameters.AddWithValue("@" + item.Key, item.Value); 
     } 

     DataTable table = new DataTable(); 
     using (var reader = cmd.ExecuteReader()) 
     { 
      table.Load(reader); 
      return table; 
     } 
    } 
} 

und dann Funktion wie folgt verwendet werden:

DataTable dt = SqlComm.SqlDataTable(
    "SELECT * FROM Users WHERE UserName = @UserName AND Password = @Password", 
    new Dictionary<string, object> 
    { 
     { "UserName", login.Text }, 
     { "Password", password.Text }, 
    } 
); 

if (dt.Rows.Count > 0) 
{ 
    // do something if the query returns rows 
} 
+1

Irgendein Grund für den Downvote? –

+0

Danke für die Hilfe. Es gab viele hilfreiche Informationen von allen, aber ich dachte mir, ich würde dies als die Antwort markieren, da sie direkt mit meinem ursprünglichen Ziel in Verbindung stand. Ich werde jedoch alle Vorschläge prüfen, um mehr über diesen Prozess zu erfahren. Vielen Dank! – Cineno28

+0

@Darin Dimitrov, 'foreach (Zeichenfolgenelement in Werten)' Ist es möglich? – Jeyhun

-2

Mein Vorschlag: Verwenden Sie eine ORM. Es gibt viele zur Auswahl von jetzt an Tagen

+1

Warum sollte ein ORM verwendet werden, wenn ADO.NET bereits über alles verfügt, was erforderlich ist, um die SQL-Injektion zu verhindern? Ein ORM könnte manchmal ein Overhead sein. –

+0

@darindimitrov Ich streite diesen Punkt nicht, nur darauf hinweisend, dass das, was er tut, genau das Problem ist, das ORMs lösen. Sicher kann es eine Leistungseinbuße geben (hängt vom ORM ab), aber es ist nichts im Vergleich zu dem Schaden, den die SQL-Injection verursachen kann - Greife alle Produktivitätsgewinne und all das auf. Schließlich, da das OP erwähnt hat, dass er "neu" sei, habe ich eine Option vorgeschlagen, die freundlicher für jemanden ist, der gerade erst anfängt. – iamkrillin

0

Was Sie versuchen zu tun macht logischen Sinn und ich kann verstehen, warum Sie bei dieser Implementierung ankommen würden. Was Sie jedoch versuchen, ist sehr gefährlich. Wenn Sie ASP.NET neu kennen, werden Sie möglicherweise nicht wissen, dass Ihnen eine Vielzahl anderer Optionen zur Verfügung steht, die die Verwaltung Ihrer Daten wesentlich einfacher und sicherer machen.

@amykrillin angedeutet eine solche Technologie - Object Relational Mapping (ORM). Das .NET-Framework hat eine erstklassige Unterstützung für ein ORM namens Entity Framework. Ich glaube der Grund, warum er vorgeschlagen hat, dass Sie in ein ORM schauen, liegt darin, dass Ihr Design eigentlich sehr ähnlich zu ORMs Arbeit ist. Sie sind abstrahierte Klassen, die Tabellen in Ihrer Datenbank darstellen, die leicht mit LINQ abgefragt werden können. LINQ-Abfragen werden automatisch parametrisiert und entlasten Sie bei der Verwaltung der Sicherheit Ihrer Abfragen. Sie generieren SQL im laufenden Betrieb (genau so, wie Sie es tun, wenn Sie Zeichenfolgen an Ihre Datenzugriffsklasse übergeben) und sind viel flexibler in der Art und Weise, wie sie Daten zurückgeben können (Arrays, Listen, Sie nennen sie).

Ein Nachteil der ORMs ist jedoch, dass sie ziemlich steile Lernkurven haben. Eine einfachere Option (obwohl etwas älter als EF) wäre die Verwendung von typisierten Datasets. Typisierte Datasets sind viel einfacher zu erstellen als stehende ORMs und sind im Allgemeinen viel einfacher zu implementieren. Obwohl sie nicht so flexibel wie ORMs sind, erreichen sie genau das, was Sie auf einfache, sichere und bereits gelöste Weise versuchen. Zum Glück, als ASP.NET zum ersten Mal kam Training Videos konzentriert sich stark auf typisierte Datensätze und als solche gibt es eine Vielzahl von hochwertigen freely available videos/tutorials, um Sie schnell zum Laufen zu bringen.

+2

Wenn Sie kein beschissenes ORM wie Entity Framework verwenden wollen. Wählen Sie, es gibt Haufen. NHibernate, Lichtgeschwindigkeit. Und Milliarden von Mikro-ORMs wie PetaPoco, Massive, ServiceStack.Ormlite, Dapper ... – Phill

+0

Ist die Entität so schlecht? – Ryan

+0

Ja, es ist so schlimm. –

0

Sie sind auf dem richtigen Weg, und ich habe tatsächlich getan, was Sie selbst suchen. Anstatt jedoch nur einen String an Ihre Funktion zu übergeben, übergebe ich ein SQL-Command-Objekt ... Auf diese Weise können Sie alle Ihre Befehle und Parameter richtig aufbauen und dann sagen ... hier, rennen Sie das, es ist bereit zu gehen. So etwas wie

public static DataTable SqlDataTable(SqlCommand cmd) 
{ 
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString)) 
    { 
     cmd.Connection = conn; // store your connection to the command object.. 
     cmd.Connection.Open(); 
     DataTable TempTable = new DataTable(); 
     TempTable.Load(cmd.ExecuteReader()); 
     return TempTable; 
    } 
} 

public DataTable GetMyCustomers(string likeName) 
{ 
    SqlCommand cmd = new SqlCommand(); 
    cmd.CommandText = "select * from SomeTable where LastName like "@someParm%"; 
    cmd.Parameters.Add("whateverParm", likeName); // don't have SQL with me now, guessing syntax 

    // so now your SQL Command is all built with parameters and ready to go. 
    return SqlDataTable(cmd); 
} 
Verwandte Themen