2011-12-19 28 views
8

Tôi đã nghe mọi người nói (liên quan đến C#/SQL Server, nhưng cũng liên quan đến PHP/MySql): Không thoát chuỗi theo cách thủ công - sử dụng các thủ tục đã lưu thay thế.Tại sao mysql_real_escape_string() không nên tránh bất kỳ SQL Injection nào?

Ok, tôi có thể chấp nhận đề xuất này, nhưng tại sao? Nhiều người nói (kể cả trên SO) mysql_real_escape_string() là khá đủ, mysql_real_escape_string() là tốt, mysql_real_escape_string() là cách bảo vệ đầu tiên.

Tại sao? Có trường hợp nào mysql_real_escape_string() có thể không thành công không? Ít nhất một ... Tôi không cần nhiều :)

+8

Điểm yếu lớn nhất là _you_ có thể quên sử dụng! –

+0

Bạn sẽ thấy ít sử dụng các thủ tục lưu sẵn trong MySQL hơn là trong SQL Server, nhưng việc sử dụng các câu lệnh chuẩn bị thường là những gì được khuyến khích với PHP/MySQL APIs. –

+1

Tôi chưa từng gặp vấn đề gì khi sử dụng mysql_real_escape_string(). Tôi nghĩ mọi người nói để sử dụng quy trình cửa hàng thay vì là có cơ hội để quên sử dụng mysql_real_escape_String(). – Khronos

Trả lời

1

Chỉ để biết thông tin: mysql_real_escape_string() không thoát %_. Đây là các ký tự đại diện trong MySQL nếu được kết hợp với LIKE, GRANT, or REVOKE.

3

Có hai điều mà có thể đi sai với mysql_real_escape_string:

  • Bạn có thể quên sử dụng nó
  • Nếu bạn đang sử dụng một số mã hóa kết nối multibyte cụ thể, và bạn đã thiết lập các mã hóa với SET NAMES thay vì mysql_set_charset như là thích hợp, nó vẫn có thể để lại cho bạn dễ bị tổn thương

cập nhật:

  • Bạn đang an toàn với UTF-8 (mặc dù này không có nghĩa là bạn nên tiếp tục sử dụng SET NAMES!)
  • Đối với một lời giải thích, xem here
+0

Bạn có thể cho tôi một ví dụ về điểm thứ hai không?Tôi sử dụng SET NAMES với UTF8, và nó có an toàn không? – markzzz

+0

@markzzz: Xem câu trả lời cập nhật – Jon

+0

Điều thứ ba: bạn có thể nhớ sử dụng nó, làm như vậy khi không bên trong dấu ngoặc kép. – Cheekysoft

0

mysql_real_escape_string()có thể thất bại để làm sạch đầu vào. Kể từ khi mysql_real_esacpe_string() tính đến ký tự trong khi làm sạch chuỗi. Có vấn đề. Bạn có thể thay đổi ký tự thông qua chức năng mysql_query gửi truy vấn để thay đổi bộ ký tự của kết nối. Tuy nhiên, mysql_real_escape_string() không biết gì về bộ bạn đang sử dụng và nó sẽ thoát khỏi một số ký tự không đúng cách.

Điều khác liên tục gọi nó theo cách thủ công. Thậm chí gói nó trong một hàm là một P.I.T.A. bởi vì nó ngụ ý bạn phải tạo ra một số loại cơ sở dữ liệu wrapper/cơ sở dữ liệu lớp trừu tượng của riêng bạn để có thể tự động hóa các cuộc gọi đến mysql_real_escape_string().

Đó là lý do tại sao chúng tôi có PDO trong PHP giúp chúng tôi giảm bớt tất cả các điều trên và bạn sử dụng các câu lệnh đã chuẩn bị theo yêu cầu cách thích hợp hơn với các truy vấn lặp lại làm thay đổi dữ liệu.

Chuẩn bị tuyên bố, ràng buộc biến đầu vào và nó sẽ làm sạch đầu vào theo trình điều khiển cơ sở dữ liệu đang được sử dụng và bộ ký tự của kết nối. Nó ít mã và hoàn toàn an toàn.

+0

Không có gì hoàn toàn an toàn, ngay cả PDO. I E. nó không có cơ chế để sử dụng tên bảng và cột làm thông số, do đó bạn sẽ sử dụng phương pháp vệ sinh thủ công để ngăn ngừa tiêm, ngay cả với PDO. – brezanac

+0

@holodoc - nếu bạn thấy mình cần phải ràng buộc tên cột và bảng thông qua PDO ngụ ý bạn đang nhận tên cột/bảng từ đầu vào của người dùng, điều này càng ngụ ý rằng cách bạn đang thực hiện đơn giản là sai. Nếu không, nếu bạn đã mã hóa col./tables của bạn trong một mảng DBAL của bạn, thì cần kiểm tra thêm xem chúng có gây ra lỗi sql hay không? PDO là hoàn toàn an toàn để tiết kiệm đầu vào của người dùng. mysql_real_escape có một vài lỗi và chúng đã được chỉ ra. –

+0

Tại sao việc sử dụng tên cột và bảng động ngụ ý rằng những tên đó được lấy ra từ đầu vào của người dùng? Có rất nhiều trường hợp để đặt tên các tên bảng/cột được xác định bằng điều khiển luồng đơn giản. – brezanac

9

Khi mysql_real_escape_string FAIL:

$sql = "SELECT * FROM users WHERE id=" + mysql_real_escape_string($_GET['id']); 

Nếu $_GET['user_id'] được thiết lập để 1 OR 1 = 1, không có ký tự đặc biệt và nó không được lọc.

Kết quả: Tất cả các hàng được trả lại.

Nó trở nên tồi tệ hơn. Làm thế nào về điều này ... nếu $_GET['user_id'] được đặt thành 1 HOẶC is_admin = 1?

Chức năng này chỉ được thiết kế để sử dụng khi nằm trong dấu nháy đơn.

+0

Tôi thấy điều này thường xuyên trong tự nhiên – Cheekysoft

+0

Yeah! Thông thường nếu tôi khía cạnh một int, tôi kiểm tra trước nếu $ _GET ['user_id'] là int! Yeah, tất nhiên tôi nên sử dụng PDO để tránh những kiểm tra này ... – markzzz

+0

alright, điều này cũng sẽ thất bại với PDO, anyway ......: O – markzzz

0

Chỉ có một điều về mysql_real_escape_string() và SQL Injection -

Các cựu không có một mối quan hệ nhỏ để sau này.

Mặc dù nghe có vẻ nghịch lý nhưng không có gì có thể đúng hơn.

Dưới đây là 2 báo cáo chứng minh nó

  1. Bạn phải thoát khỏi chuỗi trích dẫn mà thôi, như chức năng này giúp có gì khác.
  2. Thực tế, bạn phải thoát khỏi mỗi chuỗi mà bạn đang thêm vào truy vấn, thậm chí là chuỗi an toàn nhất. chỉ vì nó có thể chứa một số ký tự đặc biệt và do đó phá vỡ các truy vấn (giống như một tai nạn, không âm mưu độc hại).

Do đó, khi áp dụng, chức năng này phải được sử dụng dù sao, bất kể nguy hiểm hay lo ngại nào. Và trong mọi trường hợp khác, nó sẽ không giúp gì cả.

Điều duy nhất tôi phải thêm là các câu lệnh đã chuẩn bị cũng không cung cấp sự bảo vệ đầy đủ. Dưới đây là giải thích và đề xuất: https://stackoverflow.com/a/8255054/285587

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