2017-05-18 24 views
1

データを処理してSQL Serverに格納する必要があるC#プログラムがあります。私が抱えている問題は、保存されているデータの一部に合法的に一重引用符が含まれていることです。データを保存するときには、一重引用符を含む項目を探し、二重引用符で一重引用符を置き換えて、切り捨てられた文字列を取得しないようにする必要があります。シングルクォートを含むSQL Serverに文字列データを保存する最も良い方法は何ですか

私は私がFSQという静的モジュールに持って次のルーチンを通過させています単一引用符が含まれている可能性のあるデータを追加していwhereever現時点では、このルーチンである(単一引用符を修正):

/// <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) 

これは機能し、私の文字列はOKにSQLに保存されますが、このルーチンへの呼び出しがたくさんあるので、プログラムは処理中に何千もの行のデータをループします。

この関数を呼び出す必要性を否定するより効率的なルーチンがありますか?ほとんどの場合、これらの項目を含むクエリを更新または挿入するだけです。

助けてください。

+8

なんてこった。 'SqlCommand' +' SqlParamater'は、自動的にエスケープ処理を行うことで、これを問題にならないでしょう。 –

+0

また、私が '' '' 'を渡すことができれば、それは置換を実行することをスキップし、それでも不一致の引用符が許されることに注意してください。 –

+1

@InnovaITveSolutionsいいえ、これは複製として使用するべきではありません。なぜなら、OPはC#からそれをやっているからです。この場合、文字列の一重引用符をエスケープすると、SQLインジェクションの招待状となります。 – dasblinkenlight

答えて

2

を処理するために適用する必要があり、このような攻撃を回避するために従うことができ、様々な消毒技術があります。決してあなた自身の物を脱出することはありません。あなたは攻撃可能なコード(SQLインジェクション)を100%得ます。

使用しているDBアダプタによっては、パラメータ化されたクエリを使用できます。ここ

はado.netを使用したサンプルである:

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

クエリ内@city、後でドライバレベルに置き換えられるプレースホルダ、あろう。

+0

誰かがSQLインジェクション攻撃を実行しようとするとどうなるのでしょうか? try catchの中で "吹き飛ばす" "cmd"はすべてがOKならチェックするべきいくつかのプロパティを持っていますか? –

+0

ドライバレベルでは置き換えられません。コマンドがSQL Serverに到着すると、コマンドテキストとパラメータは依然として異なる概念です。それが私たちが望むものです。 SQL Server *は、パラメータが純粋にデータであり、コマンドの一部としてそれらを誤って解釈する機会がないことを知っています。 –

+0

はい、あなたは正しいです。私はその言葉を初心者にもっと明確にするために使用しました。 –

-1

これはあなたが達成できる最も速い方法です。

+0

http://rextester.com/FFQP43481 – user8030929

+1

まだ元の多くの欠陥の1つが含まれています - 文字列に '' 'が含まれていれば置換されずにそのまま渡すことができるので、 dはまだこの文字列にエスケープされていない引用符を持っています。 –

+0

ありがとうございます、私がここに投稿した結果として使用するテクニックではありませんが、有用なコーディングスニペットの私のキットバッグのどこかで役に立つかもしれませんが、全体的なコンセンサスは、単一引用符を取り除く必要性があります。パフォーマンスは私の主な関心事です。私がやっているやり方は、現在、膨大な時間を費やしています。 – Siv

0

varchar/nvarcharパラメータとしてSQL Serverに渡す場合は問題ありません。あなたは 'to'を置き換える必要はありません。

+0

処理されるデータはnvarcharで、nvarcharとして格納されます。データにはASCII以外の文字が含まれる可能性があります。 – Siv

+0

あなたはどんな文字も置き換えてはいけません。文字列をそのまま送ります。 – Ravi

0

文字列データを扱う際には、SQLインジェクション攻撃のためにSQL Serverでの処理方法に非常に注意する必要があります。 SQL Inject Attackは、攻撃者が悪意のあるデータベースにSQL文を実行する不正なテキストを入力する攻撃を指します。

のは、あなたが製品テーブルを持っており、以下の言ってみましょうあなたは、攻撃者I入力してもよく、「スマートフォンOR 1 = 1」として

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

を処理するために書かれている可能性があり、そのクエリを見ることができるクエリです製品表のすべての製品のリストが表示されます。

あなたはあなたがあなたのコード内のSQLステートメントを構築するためにしようとしないような攻撃に

SQL Injection Prevention Cheat Sheet

+0

ニースは知っています。説明がありがたいです –

+0

EntityフレームワークのようなORMについて聞かせてもよろしいですか? SQLインジェクション攻撃を防ぐために何かする必要がありますか? –

+0

危険なサンプル。SQLインジェクションについて説明しても、人々はコードをコピー&ペーストする傾向があるからです。その後、彼らはフィルタリングすることを忘れていますパラメータを使用する方が節約です。 –

0

まず、Dependency Injectionを使用して処理コードを永続性から切り離す必要があります。
その後、処理されたデータは、適切なインタフェースを介してANY DBMSによってSystem.Stringおよび消耗品として公開されます。
次に、SQL Serverに永続化したいとします。エンティティフレームワークを使用するつもりです。エンティティフレームワークは、エスケープ文字を処理します。具体的には、(文字列の)データをどこに格納するかを知っているからです...少なくとも私は仮定します。これは私がやることです!私より経験豊富な人がこれが間違った道だと思っているなら、私を修正してください。

0

以下は、INSERT、DELETE、またはUPDATEの操作でアポストロフィを処理する独自のメソッドを作成しようとするのではなく、パラメータを使用することに関する以前の返答に沿っています。以下は簡単です。パラメータを使用して新しいレコードを追加し、新しい主キーを返します。

最初の挿入にはアポストロフィが1つあり、2番目の挿入は1つです。下のクラスはクラスプロジェクトにあり、フォームの2番目のコードブロックはクラスプロジェクトを参照するフォームプロジェクト内にあります。

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; 
     } 
    } 
} 

フォームコード(モック/静的データ)

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

コメントをいただきありがとうございます。この例ではSQL Serverを使用していますが、コードではパラメータの処理方法を強調しています。ここではすべての文章を読んでから問題を解決します。 – Siv

+0

こんにちは、私はあなたにSQL Serverを与えていましたが、あなたの最初の投稿には、「Access Accessデータベースを混乱させる」というコメントがあります。私が行ったより大きいMSDNコードサンプルの一部である下のコードサンプルを参照してください。 https://code.msdn.microsoft.com/Adding-new-records-into-bff5eaaf/sourcecode?fileId=124530&pathId=772259264 –

関連する問題