2009-02-12 2 views
82

Tôi đã nghe nói rằng "mọi người" đang sử dụng các truy vấn SQL được tham số hóa để bảo vệ chống lại các cuộc tấn công SQL injection mà không phải vailidate mọi phần nhập của người dùng.Làm cách nào để tạo truy vấn SQL được tham số hóa? Tại sao phải là tôi?

Bạn làm như thế nào? Bạn có tự động nhận được điều này khi sử dụng các thủ tục được lưu trữ không?

Vì vậy, hiểu biết của tôi đây là phi tham số:

cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz) 

này sẽ được tham số?

cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz) 

Hoặc tôi có cần phải làm gì đó rộng hơn như thế này để bảo vệ bản thân mình khỏi việc tiêm SQL không?

With command 
    .Parameters.Count = 1 
    .Parameters.Item(0).ParameterName = "@baz" 
    .Parameters.Item(0).Value = fuz 
End With 

Có lợi ích nào khác khi sử dụng truy vấn được tham số hóa bên cạnh các cân nhắc bảo mật không?

Cập nhật: Bài viết tuyệt vời này được liên kết trong một trong các câu hỏi được Grotok tham khảo. http://www.sommarskog.se/dynamic_sql.html

+0

Tôi thấy điều đó gây sốc khiến dường như câu hỏi này chưa được hỏi trên Stackoverflow trước đây. Rất tốt! –

+3

Ồ, nó có. Có rất nhiều từ, tất nhiên, nhưng nó có. –

+0

Vui lòng không sử dụng khối "Có". Không bao giờ. "Với" là một trong những lý do mà rất nhiều người có một sự không thích mạnh đối với VB. – yfeldblum

Trả lời

67

dụ EXEC của bạn sẽ không được tham số. Bạn cần truy vấn tham số (chuẩn bị phát biểu trong một số vòng tròn) để ngăn chặn đầu vào như thế này từ gây thiệt hại:

'; DROP TABLE thanh; -

Hãy thử đặt rằng trong biến fuz của bạn (hoặc don 't, nếu bạn coi trọng bảng thanh của bạn). Các truy vấn tinh vi và gây hại khác cũng có thể xảy ra.

Dưới đây là một ví dụ về cách bạn làm thông số với Sql Server:

Public Function GetBarFooByBaz(ByVal Baz As String) As String 
    Dim sql As String = "SELECT foo FROM bar WHERE baz= @Baz" 

    Using cn As New SqlConnection("Your connection string here"), _ 
     cmd As New SqlCommand(sql, cn) 

     cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz 
     Return cmd.ExecuteScalar().ToString() 
    End Using 
End Function 

Stored procedures đôi khi được ghi nhận với việc ngăn chặn SQL injection. Tuy nhiên, hầu hết thời gian bạn vẫn phải gọi cho họ bằng cách sử dụng các tham số truy vấn hoặc họ không giúp đỡ. Nếu bạn sử dụng thủ tục lưu trữ độc quyền, thì bạn có thể tắt quyền cho SELECT, UPDATE, ALTER, CREATE, DELETE, v.v. (chỉ là về mọi thứ trừ EXEC) cho tài khoản người dùng ứng dụng và nhận được một số bảo vệ theo cách đó.

+0

Bạn có thể giải thích thêm về 'cmd.Parameters.Add (" @ Baz ", SqlDbType.VarChar, 50) .Value = Baz' không? –

+1

@CaryBondoc, bạn muốn biết điều gì? Dòng đó tạo ra một tham số gọi là '@ Baz' có kiểu' varchar (50) 'được gán giá trị của chuỗi' Baz'. –

+0

bạn cũng có thể nói "command.parameters.addiwthvalue (" @ Baz ", 50)" –

5

Bạn muốn đi với ví dụ cuối cùng của bạn vì đây là ví dụ duy nhất thực sự được tham số. Bên cạnh các vấn đề bảo mật (điều mà bạn có thể nghĩ nhiều), tốt nhất là hãy để ADO.NET xử lý parametrization vì bạn không thể chắc chắn liệu giá trị bạn truyền có yêu cầu một dấu nháy đơn hay không mà không kiểm tra Type của mỗi tham số.

[Chỉnh sửa] Dưới đây là một ví dụ:

SqlCommand command = new SqlCommand(
    "select foo from bar where baz = @baz", 
    yourSqlConnection 
); 

SqlParameter parameter = new SqlParameter(); 
parameter.ParameterName = "@baz"; 
parameter.Value = "xyz"; 

command.Parameters.Add(parameter); 
+3

Becareful với điều này:. Net strings là unicode, và do đó tham số sẽ giả định NVarChar theo mặc định.Nếu nó thực sự là một cột VarChar, điều này có thể gây ra vấn đề hiệu suất lớn. –

1

văn bản lệnh của bạn cần phải được như:

cmdText = "SELECT foo FROM bar WHERE baz = ?" 

cmdText = "EXEC foo_from_baz ?" 

Sau đó thêm giá trị tham số.Cách này đảm bảo rằng giá trị con chỉ kết thúc được sử dụng làm giá trị, trong khi với phương thức khác nếu biến fuz được đặt thành

"x'; delete from foo where 'a' = 'a" 

bạn có thể xem điều gì có thể xảy ra không?

2

Hầu hết mọi người sẽ thực hiện việc này thông qua thư viện ngôn ngữ lập trình phía máy chủ, như PDO hoặc Perl DBI của PHP.

Ví dụ, trong PDO:

$dbh=pdo_connect(); //you need a connection function, returns a pdo db connection 

$sql='insert into squip values(null,?,?)'; 

$statement=$dbh->prepare($sql); 

$data=array('my user supplied data','more stuff'); 

$statement->execute($data); 

if($statement->rowCount()==1){/*it worked*/} 

này sẽ chăm sóc của thoát dữ liệu của bạn để chèn cơ sở dữ liệu.

Một lợi thế là bạn có thể lặp lại một lần chèn nhiều lần với một tuyên bố đã chuẩn bị, đạt được lợi thế về tốc độ. Ví dụ, trong truy vấn trên, tôi có thể chuẩn bị câu lệnh một lần, và sau đó lặp lại việc tạo mảng dữ liệu từ một loạt dữ liệu và lặp lại -> thực hiện nhiều lần khi cần thiết.

14

Chắc chắn là thứ hai.

truy vấn parametrized có hai ưu điểm chính:

  • An ninh: Đó là một cách tốt để tránh SQL Injection lỗ hổng
  • Hiệu suất: Nếu bạn thường xuyên gọi cùng một truy vấn chỉ với các thông số khác nhau một truy vấn parametrized có thể cho phép các cơ sở dữ liệu để lưu trữ các truy vấn của bạn, đây là một nguồn đáng kể về hiệu năng.
  • Thêm: Bạn sẽ không phải lo lắng về các vấn đề về định dạng ngày và giờ trong mã cơ sở dữ liệu của mình. Tương tự, nếu mã của bạn sẽ chạy trên các máy có ngôn ngữ không phải tiếng Anh, bạn sẽ không gặp vấn đề với dấu thập phân/dấu phẩy thập phân.
+0

Tôi hy vọng bài đăng này được viết lại khi "bài thứ hai" là nội dung khác. Vì nó hiện đang đứng, câu trả lời này đã chết sai! –