2016-02-02 20 views
36

Tôi đang cố gắng tạo một câu lệnh SQL sử dụng dữ liệu do người dùng cung cấp. Tôi sử dụng mã tương tự như sau:Làm cách nào để thêm đầu vào do người dùng cung cấp vào câu lệnh SQL?

var sql = "INSERT INTO myTable (myField1, myField2) " + 
      "VALUES ('" + someVariable + "', '" + someTextBox.Text + "');"; 

var cmd = new SqlCommand(sql, myDbConnection); 
cmd.ExecuteNonQuery(); 

Tuy nhiên,

  • này không thành công khi đầu vào người sử dụng có chứa dấu nháy đơn (ví dụ O'Brien),
  • tôi dường như không thể có được định dạng phù hợp khi chèn DateTime các giá trị và
  • mọi người tiếp tục nói với tôi rằng tôi không nên làm điều này vì "SQL injection".

Làm cách nào để làm điều đó "đúng cách"?

+5

Lưu ý: Câu hỏi này có nghĩa là như một câu hỏi kinh điển cho những người không thể có được SQLs chuỗi nối của họ để làm việc. [Nếu bạn muốn thảo luận, đây là câu hỏi meta tương ứng.] (Http://meta.stackoverflow.com/q/315913/87698) – Heinzi

+2

Nếu bạn muốn có cái nhìn sâu sắc hơn về "SQL Injection" là gì và tại sao lại nguy hiểm khi thấy câu hỏi: "[Làm thế nào tôi có thể giải thích SQL injection mà không có thuật ngữ kỹ thuật?] (http://security.stackexchange.com/questions/25684/how-can-i-explain-sql-injection-without- thuật ngữ kỹ thuật) "từ trang web chị em bảo mật thông tin của chúng tôi. –

+1

Bạn nên wiki này, btw. – Will

Trả lời

42

Sử dụng SQL được tham số hóa.

Ví dụ

Thay concatenations chuỗi của bạn với @... placeholders và, sau đó, thêm các giá trị để SqlCommand của bạn. Bạn có thể chọn tên của trình giữ chỗ một cách tự do, chỉ cần đảm bảo rằng chúng bắt đầu bằng ký hiệu @. Ví dụ bạn sẽ trông như thế này:

var sql = "INSERT INTO myTable (myField1, myField2) " + 
      "VALUES (@someValue, @someOtherValue);"; 

using (var cmd = new SqlCommand(sql, myDbConnection)) 
{ 
    cmd.Parameters.AddWithValue("@someValue", someVariable); 
    cmd.Parameters.AddWithValue("@someOtherValue", someTextBox.Text); 
    cmd.ExecuteNonQuery(); 
} 

Các mô hình tương tự được sử dụng cho các loại câu lệnh SQL:

var sql = "UPDATE myTable SET myField1 = @newValue WHERE myField2 = @someValue;"; 

// see above, same as INSERT 

hoặc

var sql = "SELECT myField1, myField2 FROM myTable WHERE myField3 = @someValue;"; 

using (var cmd = new SqlCommand(sql, myDbConnection)) 
{ 
    cmd.Parameters.AddWithValue("@someValue", someVariable); 
    using (var reader = cmd.ExecuteReader()) 
    { 
     ... 
    } 
    // Alternatively: object result = cmd.ExecuteScalar(); 
    // if you are only interested in one value of one row. 
} 

Một lời cảnh báo: AddWithValue là tốt điểm khởi đầu và hoạt động tốt trong hầu hết các trường hợp. Tuy nhiên, giá trị bạn vượt qua cần phải khớp chính xác với kiểu dữ liệu của trường cơ sở dữ liệu tương ứng. Nếu không, bạn có thể kết thúc trong trường hợp chuyển đổi ngăn truy vấn của bạn từ using an index. Lưu ý rằng một số kiểu dữ liệu SQL Server, chẳng hạn như char/varchar (không có trước "n") hoặc ngày không có kiểu dữ liệu .NET tương ứng. Trong những trường hợp đó, Add with the correct data type should be used instead.

Tại sao tôi nên làm điều đó?

  • It's more secure: Nó dừng SQL injection. (Bobby Tables won't delete your student records.)

  • Nó dễ dàng: Không cần phải fiddle xung quanh với dấu nháy đơn và đôi hoặc để tìm kiếm chuỗi đại diện đúng các chữ ngày.

  • Nó ổn định hơn: O'Brien sẽ không làm hỏng ứng dụng của bạn chỉ vì anh ấy khăng khăng giữ tên kỳ lạ của mình.

Khác thư viện truy cập cơ sở dữ liệu

  • Nếu bạn sử dụng một OleDbCommand thay vì một SqlCommand (ví dụ, nếu bạn đang sử dụng cơ sở dữ liệu MS Access), hãy sử dụng ? thay vì @... làm trình giữ chỗ trong SQL. Trong trường hợp đó, tham số đầu tiên của AddWithValue không liên quan; thay vào đó, bạn cần phải thêm các tham số theo đúng thứ tự. The same is true for OdbcCommand.

  • Entity Framework also supports parameterized queries.

+0

Cẩn thận với tuyên bố "loại khác" - SELECT sẽ không hoạt động với 'cmd.ExecuteNonQuery()' – Hogan

+0

@Hogan: True. Tôi nghĩ về việc đưa ra một ví dụ hoàn chỉnh hơn, nhưng vì câu trả lời này chủ yếu là về việc chuyển từ SQL ghép chuỗi thành SQL được tham số hóa, tôi không muốn làm nổi bật câu trả lời bằng cách thêm quá nhiều mã "sẽ không thay đổi" (nếu nó là ExecuteScalar trước đó, nó là ExecuteScalar sau đó). – Heinzi

+0

@Heinze - Tôi nghĩ rằng tôi muốn một điểm bullet ngắn trong trường hợp đặc biệt nói một cái gì đó như "sử dụng các thông số sẽ làm việc ngay cả khi bạn đang làm 'ExecuteQuery(), ExecuteReader(), ExecuteScalar()' hoặc những người khác. – Hogan

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