2010-05-05 25 views
7

Ý tưởng của tôi là tạo một số lớp chung cho Chèn/Cập nhật/Chọn qua ứng dụng Winforms C# (3.5) nói chuyện với cơ sở dữ liệu MySQL thông qua MySQL .NET Connector 6.2.2.C# và MySQL .NET Connector - Bất kỳ cách nào ngăn chặn các cuộc tấn công SQL Injection trong một lớp chung?

Ví dụ:

public void Insert(string strSQL) 
{ 
    if (this.OpenConnection() == true) 
    { 
     MySqlCommand cmd = new MySqlCommand(strSQL, connection); 
     cmd.ExecuteNonQuery(); 
     this.CloseConnection(); 
    } 
} 

Sau đó từ bất cứ nơi nào trong chương trình tôi có thể chạy một truy vấn có/không có người dùng nhập vào bằng cách chỉ cần đi qua một chuỗi truy vấn SQL.

Đọc xung quanh trên SO đang bắt đầu cho tôi chỉ báo rằng điều này có thể dẫn đến tấn công SQL injection (đối với bất kỳ giá trị người dùng nhập nào). Có anyway của chà strSQL đầu vào hoặc tôi cần phải đi và tạo ra các truy vấn tham số cá nhân trong mọi phương pháp mà cần phải làm một chức năng cơ sở dữ liệu?

UPDATE1:

giải pháp cuối cùng của tôi trông giống như sau:

public void Insert(string strSQL,string[,] parameterValue) 
{ 
    if (this.OpenConnection() == true) 
    { 
     MySqlCommand cmd = new MySqlCommand(strSQL, connection); 

     for(int i =0;i< (parameterValue.Length/2);i++) 
     {       
     cmd.Parameters.AddWithValue(parameterValue[i,0],parameterValue[i,1]);   
     } 

     cmd.ExecuteNonQuery(); 
     this.CloseConnection(); 
    }} 
+1

Ý tưởng khủng khiếp này la hét. Bạn nên sử dụng ORM hoặc viết procs được lưu trữ. –

Trả lời

9

Bạn chắc chắn nên sử dụng các truy vấn được tham số hóa để giữ cho mình an toàn.

Bạn không phải tự tạo các truy vấn được tham số hóa mỗi lần. Bạn có thể thay đổi phương pháp chung chung mà bạn cung cấp để chấp nhận một bộ sưu tập của MySqlParameters:

public void Insert(string strSQL, List<MySqlParameter> params) 
{ 
    if(this.OpenConnection() == true) 
    { 
     MySqlCommand cmd = new MySqlCommand(strSQL, connection) 
     foreach(MySqlParameter param in params) 
      cmd.Parameters.Add(param); 

     cmd.ExecuteNonQuery(); 
     this.CloseConnection(); 
    } 
} 

Tôi cũng nên đề cập rằng bạn phải rất cẩn thận về dọn dẹp kết nối của bạn sau khi bạn đã hoàn tất việc sử dụng chúng (thường là xử lý trong một using chặn, nhưng tôi không thấy mức độ chi tiết đó trong ví dụ mã của bạn).

+0

Cảm ơn Justin - Tôi đã bắt đầu nghĩ ra một cách để lai tạo một lớp chung với các truy vấn được tham số hóa nhưng bạn đã đánh bại tôi với nó. Bạn có thể làm rõ ý nghĩa của một khối sử dụng không? –

+0

bạn có thể dạy tôi làm thế nào tôi có thể sử dụng wrapper sql này? thanks =) –

1

Nó không thể phát hiện SQL injection sau khi thực tế (hay nói cách khác, một khi bạn đã xây dựng một chuỗi truy vấn năng động , nó không thể phân biệt những gì "thực sự" SQL là so với bất kỳ SQL tiêm).

Nếu ý định của bạn là cho phép người dùng thực thi SQL tùy ý, thì có vẻ như bạn sẽ không quá lo lắng về việc tiêm SQL (vì đó là nhằm mục đích của SQL injection).

+0

Cảm ơn @Adam - Tôi đã không nghĩ về cách đó - Tôi cho rằng có thể có một số phương pháp sử dụng Regex, v.v ... trên các truy vấn nhưng mỗi cách tiếp cận có lẽ sẽ có một lỗ hổng. –

+2

@ John: Không có cách nào chung, RegEx hoặc không. Bất cứ phương pháp nào bạn sử dụng sẽ phải biết * một cái gì đó * về cách truy vấn/câu lệnh * nên * nhìn, vì vậy không có cách nào để thực hiện nó theo cách trung lập theo ngữ cảnh. –

1

Tôi hy vọng rằng sẽ rất khó khăn để quét văn bản thô sẽ được sử dụng cho SQL. Nếu có thể tôi sẽ cố gắng sử dụng các hoạt động tham số hóa.

Một ngoại lệ sẽ là nếu bạn không hiển thị công khai hàm và bạn không bao giờ chuyển một chuỗi được tạo từ đầu vào của người dùng thô.

1

nếu bạn sử dụng MySqlParameter và không tạo các truy vấn chuỗi đơn giản, bạn an toàn.

1

Bạn không thể thực sự làm điều này - bạn cần phải viết một trình phân tích cú pháp SQL để nói rằng ít nhất là không tầm thường và dễ bị lỗi.

Cắn viên đạn và thông số truy vấn của bạn.

1

Tôi khuyên bạn nên sử dụng các đối tượng IDataParameter để tham số hóa truy vấn của bạn.

10

Parametrization rất dễ thực hiện. Dễ dàng hơn nhiều so với việc quét các truy vấn SQL và ít lộn xộn hoặc dễ xảy ra lỗi hơn là thoát bằng tay.

Hơi sửa copy/paste từ this tutorial page bởi vì tôi cảm thấy lười biếng:

// User input here 
Console.WriteLine("Enter a continent e.g. 'North America', 'Europe': "); 
string userInput = Console.ReadLine(); 

string sql = "SELECT Name, HeadOfState FROM Country WHERE [email protected]"; 
MySqlCommand cmd = new MySqlCommand(sql, conn); 
cmd.Parameters.AddWithValue("@Continent", userInput); 

using (MySqlDataReader dr = cmd.ExecuteReader()) 
{ 
    // etc. 
} 

Đó không phải là khó khăn như vậy, đúng không? :)

+0

Cảm ơn @Thorarin - Tôi đã đi với câu trả lời của @Justin Niessner do tính chất chung của nó (Tôi không muốn kết nối/mã MySQL trong mọi phương pháp) nhưng câu trả lời của bạn chắc chắn sẽ giúp với cú pháp. –

+0

@ John M: Bạn được hoan nghênh viết các phương thức bao bọc của khóa học. Mục tiêu của tôi là cho thấy kim loại trần của nó. – Thorarin

1

CÓ bạn cần tạo truy vấn được tham số hóa, bất kỳ điều gì khác sẽ giới thiệu nguy cơ tiêm SQL

+0

Tôi sẽ không đi xa đến thế. Có những cách kín đáo để thoát khỏi đầu vào của người dùng. Thật không may là các lập trình viên chỉ là con người, và có thể quên thoát khỏi cái gì đó ... – Thorarin

+0

Câu hỏi là xử lý/chà sau khi nó được kết hợp với SQL .... tại thời điểm đó gần như không thể làm –

Các vấn đề liên quan