2017-05-18 3 views
1

Ich habe ein C# -Programm, das Daten verarbeiten und in SQL Server speichern muss. Das Problem, das ich habe, ist, dass einige der Daten, die legitim gespeichert werden, ein einzelnes Zitat enthalten. Beim Speichern der Daten muss ich die Elemente suchen, die einfache Anführungszeichen enthalten, und aktiv das einfache Anführungszeichen durch zwei einfache Anführungszeichen ersetzen, so dass ich keine abgeschnittene Zeichenfolge erhalte.Was ist die beste Möglichkeit, Zeichenfolge Daten zu SQL Server zu speichern, die einzelnes Zitat enthält

Derzeit egal wo ich Daten bin hinzufügen, die einen Apostroph enthalten könnte ich es durch die folgende Routine bin vorbei, die ich in einem statischen Modul namens FSQ (Fix Einzel Quote), das die Routine ist:

/// <summary> 
/// Fix Single Quote - Used to remove Double quotes from strings that would confuse Access database by replacing with Single Quotes. 
/// </summary> 
/// <param name="s">String text to be fixed by removing double quotes.</param> 
/// <returns>The original string with any double-quotes removed and replaced with single quotes. If an error occurs will return an empty string.</returns> 
public static string FSQ(string s) 
{ 
    string tmp =""; 

    try 
    { 
     if (s == null) 
      return ""; 

     s = s.Trim(); 

     if (s == "") 
      return s; 

     if(s.Contains("'")) 
     { 
      if(!s.Contains("''"))//Already been fixed previously so skip here 
       tmp = s.Replace("'", "''"); 

       s = tmp; 
     } 

     return s; 


    } 
    catch (Exception ex) 
    { 
     PEH("FDQ", "Common Module", ex.Message); 
     return ""; 
    } 
} //public static String FDQ(String s) 

Dies funktioniert und meine Strings werden OK in SQL gespeichert, aber da es viele Aufrufe an diese Routine gibt, ist die Leistung saugt, wie das Programm durchläuft Tausende von Zeilen von Daten während der Verarbeitung.

Gibt es eine effizientere Routine, die diese Funktion nicht aufrufen würde? Meistens baue ich nur Updates oder füge Abfragen ein, die diese Elemente enthalten.

Jede Hilfe wird geschätzt.

+8

.Argh. 'SqlCommand' +' SqlParamater' wird dies zu einem Nicht-Problem machen, indem es automatisch entkommt, weshalb Sie sie immer verwenden sollten. –

+0

Und beachte auch, wie es passiert, wenn ich es übergebe, überspringe das Ersetzen und lasse trotzdem ein unübertroffenes Anführungszeichen durch. –

+1

@InnovaITveSolutions Nein, dies sollte nicht als Duplikat verwendet werden, weil OP es von C# aus tut. In diesem Fall ist es eine Einladung zur SQL-Injection, einfache Anführungszeichen in einer Zeichenfolge zu entfernen. – dasblinkenlight

Antwort

2

NIEMALS versuchen zu bauen SQL-Anweisungen in Ihrem Code möchten gelten. Versuchen Sie niemals, sich selbst zu entkleiden. Sie erhalten bei 100% einen angreifbaren Code (sql injection).

Abhängig von Ihrem DB-Adapter, den Sie verwenden, können Sie parametrisierte Abfragen verwenden.

Hier ist ein Beispiel unter Verwendung von ado.net:

var Query = "select * from customers where city = @city"; 
var cmd = new SqlCommand(Query); 
cmd.Parameters.AddWithValue("@city", txtCity); 

Die @city in der Abfrage wird der Platzhalter sein, die später auf Treiberebene ersetzt.

+0

Darf ich fragen, was passiert, wenn jemand versucht, einen SQL-Injection-Angriff durchzuführen? Wird es "blasen" in Versuch fangen "cmd" hat eine Eigenschaft überprüft werden, ob alles in Ordnung ist? –

+0

Es wird nicht auf der Treiberebene ersetzt. Wenn der Befehl bei SQL Server eintrifft, sind der Befehlstext und die Parameter noch eindeutige Konzepte. Und das wollen wir. SQL Server * weiß, dass die Parameter reine Daten sind und keine Möglichkeit haben, sie als Teile des Befehls zu interpretieren. –

+0

Ja, Sie haben Recht. Ich habe diesen Begriff verwendet, um Einsteigern klarer zu sein. –

-1

Dies ist der schnellste Weg, den Sie erreichen können.

public static string FSQ(string s) 
{ 
     try 
    { 
     s = s.Trim(); 
     return s = (s != null && s != "")?(s.Contains("'") && !s.Contains("''"))?s.Replace("'", "''"): s:""; 

    } 
    catch (Exception ex) 
    { 
     PEH("FDQ", "Common Module", ex.Message); 
     return ""; 
    } 
} 
+0

http://rextester.com/FFQP43481 – user8030929

+1

Enthält immer noch einen der vielen Fehler des Originals - es überspringt den Ersatz, wenn der String '' ''enthält, so dass' ''' unverändert weitergegeben werden kann und Sie " In dieser Zeichenfolge ist immer noch ein Nicht-Escape-Zitat enthalten. –

+0

Danke dafür, obwohl nicht die Technik, die ich als Ergebnis des Postings hier verwenden werde, kann es nützlich sein, anderswo in meinem Kitbag nützliche Codeschnipsel, ich denke, der allgemeine Konsens ist für SQL-Parameter zu verwenden, da es sowohl die Sicherheit beantwortet Aspekt und die Notwendigkeit, einzelne Anführungszeichen zu streichen. Leistung ist mein Hauptanliegen, da die Art, wie ich es mache, derzeit einen riesigen Zeitaufwand verursacht. – Siv

0

Wenn Sie es als Varchar/Nvarchar-Parameter an SQL Server übergeben, wird es kein Problem geben. Sie müssen "to" nicht ersetzen.

+0

Die Daten, die verarbeitet werden, sind nvarchar und werden als nvarchar gespeichert, da die Daten nicht-ASCII-Zeichen enthalten können. – Siv

+0

dann müssen Sie kein Zeichen ersetzen. Sende String so wie sie ist. – Ravi

0

Beim Umgang mit Zeichenfolgedaten sollten Sie wegen SQL Injection-Angriffen sehr vorsichtig sein, wie Sie mit SQL Server umgehen. SQL Inject Attack bezieht sich auf einen Angriff, bei dem der Angreifer einen fehlerhaften Text eingibt, der zu einer böswilligen Ausführung von SQL-Anweisungen in Ihrer Datenbank führt.

Angenommen, Sie haben eine Produkttabelle haben und finden Sie die Abfrage, die Sie geschrieben haben, kann ich eingeben kann „Smart Phones OR 1 = 1“

var query = "SELECT * FROM Products WHERE ProductDesc = " + txtProductDesc; 

Als Angreifer zu handhaben und Sie können, dass die Abfrage sehen Am Ende werden alle Produkte in der Produkttabelle aufgelistet.

Es gibt verschiedene Techniken, die Sie Hygienisierung solche Angriffe verhindern folgen können, die Sie solche Angriffe behandeln

SQL Injection Prevention Cheat Sheet

+0

Gut zu wissen. Vielen Dank für die Erklärung –

+0

Darf ich Fragen über ORM, wie Entity-Framework oder so ähnlich? Sind sie sicher oder sollte ich etwas tun, um SQL-Injection-Angriffe zu verhindern? –

+0

Gefährliches Beispiel, denn selbst wenn Sie SQL-Injektionen erklären, neigen die Leute dazu, Code zu kopieren und einzufügen. Dann vergessen sie zu filtern. Die Verwendung von Parametern ist sicherer. –

0

Zunächst müssen Sie den Verarbeitungscode mithilfe von Dependency Injection von der Persistenz entkoppeln.
Danach werden Ihre verarbeiteten Daten als System.String und Verbrauchsmaterial von JEDEM DBMS über eine entsprechende Schnittstelle verfügbar gemacht.
Dann nehmen wir an, Sie möchten in der Tat auf SQL Server beibehalten werden. Wahrscheinlich werden Sie Entity Framework verwenden, das wiederum ausgehende Zeichen behandelt, da es genau weiß, wo es diese Daten (vom Typ String) speichern wird ... ich nehme zumindest an. Das würde ich tun! Wenn jemand, der erfahrener ist als ich, der Meinung ist, dass dies der falsche Weg ist, können Sie mich gerne korrigieren!

0

Der folgende Abschnitt geht mit früheren Antworten in Bezug auf die Verwendung von Parametern einher, anstatt zu versuchen, eine eigene Methode zur Verarbeitung von Apostrophen in Ihrer Operation zu schreiben, sei es INSERT, DELETE oder UPDATE. Das Folgende ist einfach, fügen Sie einen neuen Datensatz über Parameter hinzu und geben Sie den neuen Primärschlüssel zurück.

Die erste Einfügung hat einen Apostroph, die zweite drei. Die folgende Klasse befindet sich in einem Klassenprojekt, während sich der zweite Codeblock für das Formular in einem Formularprojekt befindet, das auf das Klassenprojekt verweist.

using System; 
using System.Data.OleDb; 
using System.IO; 

namespace DataLib 
{ 
    public class Operations1 
    { 
     public Exception InsertException { get; set; } 
     private OleDbConnectionStringBuilder Builder = new OleDbConnectionStringBuilder 
     { 
      Provider = "Microsoft.ACE.OLEDB.12.0", 
      DataSource = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Database1.accdb") 
     }; 
     public Operations1() 
     { 
      if (!(File.Exists(Builder.DataSource))) 
      { 
       throw new FileNotFoundException("Failed to find application's database"); 
      } 
     } 
     public bool AddNewRow(string CompanyName, string ContactName, ref int Identfier) 
     { 

      bool success = true; 
      int affected = 0; 

      try 
      { 
       using (OleDbConnection cn = new OleDbConnection { ConnectionString = Builder.ConnectionString }) 
       { 
        using (OleDbCommand cmd = new OleDbCommand { Connection = cn }) 
        { 
         cmd.CommandText = @"INSERT INTO Customer (CompanyName,ContactName) 
          VALUES (@CompanyName, @ContactName)"; 

         cmd.Parameters.AddWithValue("@CompanyName", CompanyName); 
         cmd.Parameters.AddWithValue("@ContactName", ContactName); 

         cn.Open(); 

         affected = cmd.ExecuteNonQuery(); 
         if (affected == 1) 
         { 
          cmd.CommandText = "Select @@Identity"; 
          Identfier = Convert.ToInt32(cmd.ExecuteScalar()); 
          success = true; 
         } 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       InsertException = ex; 
       success = false; 
      } 
      return success; 
     } 
    } 
} 

Formularcode (verspottet/statische Daten)

using DataLib; 
using System; 
using System.Windows.Forms; 

namespace DataLibDemo 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     private void button1_Click(object sender, EventArgs e) 
     { 
      Operations1 ops = new Operations1(); 
      int newIdentifier = 0; 
      if (ops.AddNewRow("O'brien and company", "Mary O'brien", ref newIdentifier)) 
      { 
       MessageBox.Show($"New Id for Mary {newIdentifier}"); 
      } 
      else 
      { 
       MessageBox.Show($"Insert failed: {ops.InsertException.Message}"); 
      } 

      if (ops.AddNewRow("O'''brien and company", "Mary O'brien", ref newIdentifier)) 
      { 
       MessageBox.Show($"New Id for Mary {newIdentifier}"); 
      } 
      else 
      { 
       MessageBox.Show($"Insert failed: {ops.InsertException.Message}"); 
      } 
     } 
    } 
} 

enter image description here

+0

Danke für Ihren Kommentar, in diesem Fall benutze ich SQL Server, aber Ihr Code hebt hervor, wie man die Parameter so macht, nachdem ich alle Kommentare gelesen habe, ist die Art, wie ich mein Problem beheben werde. – Siv

+0

Hallo, ich hätte Ihnen SQL-Server gegeben, aber in Ihrem ursprünglichen Beitrag gibt es einen Kommentar "Access-Datenbank verwechseln", den ich für Sie mit MS-Access genommen habe. Sehen Sie sich mein Codebeispiel an, das Teil eines größeren MSDN-Codebeispiels ist, das ich gemacht habe. https://code.msdn.microsoft.com/Adding-new-records-into-bff5eaaf/sourcecode?fileId=124530&pathId=772259264 –

Verwandte Themen