it-swarm-vi.com

SQL SQL - tại sao không thoát báo giá an toàn nữa?

SQL thô

Khi bạn đang viết SQL - cho bất kỳ thứ gì có đầu vào của con người thực sự, rất nhiều thứ đã được thực hiện để tránh bị tiêm.

Mọi người đã nghe nói về SQL tiêm đều biết rằng (tôi sẽ sử dụng PHP làm mẫu) làm một việc như thế này không an toàn:

$sql = "SELECT * FROM `users` 
.  WHERE `userName` = "{$_POST["username"]}" 
.  AND `pass` = "{$_POST["pass"]}";";

Ma thuật

Sau đó, tất nhiên, một người nào đó đã nảy ra ý tưởng sử dụng "trích dẫn thoát ma thuật" để đối phó với đầu vào chương trình không được vệ sinh một cách chính xác và trực tiếp đưa vào sql do các thực tiễn xấu. Điều này thực sự không giải quyết được vấn đề với SQL tiêm, nhưng điều đó có nghĩa là tất cả đầu vào của người dùng đã được xử lý.

Thêm dấu gạch chéo

Vì vậy, một số người đã tắt trích dẫn ma thuật. Sau đó, họ phân tích cú pháp đầu vào của người dùng trước điểm SQL thông qua addslashes(), theo lý thuyết thoát khỏi tất cả các trích dẫn và tin tặc của bạn không thể thực hiện ' OR 1=1, Nhưng ngay cả tài liệu để thêm vào cũng tự nói rằng bạn Không nên sử dụng phần bổ sung, nó nói sử dụng hàm dành riêng cho cơ sở dữ liệu, chẳng hạn như mysql_real_escape_string(), nhưng điều này vẫn được cho là không đủ bởi một số người.

Thêm dấu gạch chéo cụ thể vào Cơ sở dữ liệu

Vì vậy, chúng tôi không thể sử dụng DBMS cụ thể *_real_escape_string, Chúng tôi không thể sử dụng add slashes, Điều "trích dẫn ma thuật" gây ra nhiều vấn đề và web có đầy đủ các trích dẫn từ ngắn như :

"Một hacker chuyên dụng sẽ tìm cách nhảy qua các vòng lặp thoát trích dẫn của bạn, chỉ cần sử dụng các câu lệnh được chuẩn bị DBAL" - John Q bất kỳ lập trình viên nào

Được rồi, điều đó làm tôi sợ đủ để sử dụng các câu lệnh chuẩn bị và một DBAL. Nó không thực sự giải thích bất cứ điều gì, nhưng nó có vẻ tốt bởi vì tôi đã nghe nó rất nhiều.

Báo cáo đã chuẩn bị

Vì vậy, bây giờ chúng tôi đang sử dụng PDO hoặc DBAL từ một khung công tác hoặc một cái gì đó khác bao bọc tất cả sql của chúng tôi và đảm bảo ai đó không thể chạy tiêm sql.

Câu hỏi của tôi về cơ bản là "tại sao không?", Không phải là "tôi nên sử dụng cái gì?". Web có rất nhiều người bảo bạn sử dụng cái này hoặc sử dụng cái đó hoặc bất cứ điều gì , nhưng không có lời giải thích tại sao những điều này phải xảy ra.

Câu hỏi trực tiếp

Các câu hỏi được chỉ ra (nhắc nhở, tôi đang hỏi về SQL, PHP là một ngôn ngữ ví dụ vì đó là đại diện xấu xung quanh SQL, các khái niệm là phổ quát):

  1. Tại sao chúng ta không thể thoát tất cả đầu vào của người dùng bằng "ma thuật"?
  2. Tại sao không thêm "đủ tốt"?
  3. Có gì sai khi sử dụng các chức năng thoát dành riêng cho DB và tại sao nó tốt hơn so với addlash?
  4. Tại sao các câu lệnh được chuẩn bị với các khung và PDO được ca ngợi là tiêu chuẩn vàng của SQL? Tại sao họ tốt hơn? Tại sao tôi không thể thực hiện SQL SQL với những điều này, như tôi đã làm với các phương tiện đã đề cập trước đó? Một lập trình viên có thể không bằng cách nào đó quản lý để vẫn làm hỏng việc này không? Họ nên chú ý điều gì?
  5. Bất kỳ mối quan tâm nào khác tôi đã không đưa ra?
78
Incognito

Tại sao chúng ta không thể thoát tất cả đầu vào của người dùng bằng "ma thuật"?

Tại thời điểm phép thuật được áp dụng, không biết dữ liệu sẽ kết thúc ở đâu. Vì vậy, trích dẫn ma thuật đang phá hủy dữ liệu đó, trừ khi nó được viết không được lưu vào cơ sở dữ liệu.

Nó chỉ có thể được sử dụng trong phản hồi HTML được gửi lại cho khách hàng. Hãy nghĩ về một hình thức chưa được điền đầy đủ và do đó được hiển thị lại cho người dùng. Với các trích dẫn ma thuật, dữ liệu được nhập vào lần thử đầu tiên bây giờ sẽ được thoát SQL, điều này là vô nghĩa trên trang HTML. Thậm chí tệ hơn: trong lần gửi thứ hai, dữ liệu được SQL thoát lại.

Tại sao không thêm "đủ tốt"?

Nó có vấn đề với các nhân vật đa nhân:

' 27
\ 5c
뼧 bf 5c

Đó là hai byte, nhưng chỉ có một ký tự Unicode.

addslashes không biết gì về Unicode, nên nó chuyển đổi đầu vào bf 27 đến bf 5c 27. Nếu điều này được đọc bởi một chương trình nhận biết Unicode, thì nó được xem là '. Bùng nổ.

Có một lời giải thích tốt về vấn đề này tại http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-opes

Có gì sai khi sử dụng các chức năng thoát dành riêng cho DB và tại sao nó tốt hơn so với addlash?

Chúng tốt hơn bởi vì chúng đảm bảo rằng việc thoát diễn giải dữ liệu theo cách giống như cơ sở dữ liệu (xem câu hỏi cuối cùng).

Từ quan điểm bảo mật, chúng sẽ ổn nếu bạn sử dụng chúng cho mỗi lần nhập cơ sở dữ liệu. Nhưng họ có nguy cơ rằng bạn có thể quên một trong số họ ở đâu đó.

Chỉnh sửa : Như đã thêm getahulk: Hoặc bạn sử dụng xxx_escape_strings cho các số mà không thêm dấu ngoặc kép quanh chúng trong câu lệnh SQL và không đảm bảo rằng chúng là số thực truyền hoặc chuyển đổi đầu vào thành loại dữ liệu thích hợp /Chỉnh sửa

Từ góc độ phát triển phần mềm, chúng rất tệ bởi vì chúng làm cho việc hỗ trợ thêm cho phần mềm máy chủ cơ sở dữ liệu SQL khác trở nên khó khăn hơn rất nhiều.

Tại sao các câu lệnh được chuẩn bị với các khung và PDO được ca ngợi là tiêu chuẩn vàng của SQL? Tại sao họ tốt hơn?

PDO chủ yếu là một điều tốt cho lý do thiết kế phần mềm. Nó làm cho nó dễ dàng hơn nhiều để hỗ trợ phần mềm máy chủ cơ sở dữ liệu khác. Nó có một giao diện hướng đối tượng trừu tượng hóa nhiều sự không tương thích cụ thể của cơ sở dữ liệu.

Tại sao tôi không thể thực hiện tiêm SQL với [các câu lệnh đã chuẩn bị] này, nơi mà tôi CÓ THỂ có các phương tiện được đề cập trước đó?

Truy vấn hằng số " với các tham số biến " của các câu lệnh được chuẩn bị là điều quan trọng ở đây. Trình điều khiển cơ sở dữ liệu sẽ tự động thoát tất cả các tham số mà không cần nhà phát triển phải suy nghĩ về nó.

Các truy vấn tham số thường dễ đọc hơn các truy vấn bình thường với các tham số đã thoát vì lý do cú pháp. Tùy thuộc vào môi trường, chúng có thể nhanh hơn một chút.

Luôn luôn sử dụng các câu lệnh được chuẩn bị với các tham số là điều có thể được xác thực bằng các công cụ phân tích mã tĩnh . Một cuộc gọi bị thiếu đến xxx_escape_opes không được phát hiện một cách dễ dàng và đáng tin cậy.

Một lập trình viên không bằng cách nào đó có thể quản lý để vẫn còn điều này lên? Họ nên chú ý điều gì?

"Báo cáo đã chuẩn bị" ngụ ý rằng hằng số . Tự động tạo ra các báo cáo đã chuẩn bị - đặc biệt là với đầu vào của người dùng - vẫn có tất cả các vấn đề về tiêm.

52
Hendrik Brummermann

[1.] Tại sao chúng ta không thể thoát tất cả đầu vào của người dùng bằng "ma thuật"?

Bởi vì trích dẫn ma thuật bị phá vỡ trên hai tính:

  1. Không phải tất cả dữ liệu $ _ (YÊU CẦU/NHẬN/POST) đi vào DB. Và để bạn hiểu được ý nghĩa của nó, bạn phải thoát khỏi đầu vào.
  2. Chúng là tương đương addslashes (xem ghi chú của tôi trên [2.]), do đó chúng không thực sự an toàn.

[2.] Tại sao không thêm "đủ tốt"?

Có nhiều cách để thoát khỏi hạn chế addslashes, do đó, đó là thiếu sót về mặt cơ bản, tuy nhiên bạn cố gắng sử dụng nó.

[3.] Có gì sai khi sử dụng các chức năng thoát dành riêng cho DB và tại sao nó tốt hơn so với addlash?

Không có gì thực sự. Đó chỉ đơn giản là câu thần chú về lý do tại sao PDO/chuẩn bị "tốt hơn". Họ cách tốt hơn addslashes vì họ quan tâm đến nhiều yếu tố, bao gồm cả mã hóa. Đây là một bí mật nhỏ; PDO sử dụng chúng bên trong, nhưng không addslashes...

[4.] Tại sao các câu lệnh được chuẩn bị với các khung và PDO được ca ngợi là tiêu chuẩn vàng của SQL? Tại sao họ tốt hơn? Tại sao tôi không thể thực hiện SQL SQL với những điều này, như tôi đã làm với các phương tiện đã đề cập trước đó?

Họ không phải tiêu chuẩn vàng, họ không "an toàn" hơn so với các chức năng cụ thể của DB và bạn có thể thực hiện SQL tiêm với những cũng. Và không, bạn không thể thực hiện SQL SQL với đầu vào được khử trùng đúng cách.

Như với tất cả các công nghệ hiện có, các nhà phát triển có xu hướng phát triển xu hướng tôn giáo (cuồng tín?) Cho bất cứ điều gì "mới". Đó là lý do tại sao bạn nhận được lời khuyên Zend Certified Engineers (TM) dày dạn - không buộc bạn phải chuyển sang các báo cáo đã chuẩn bị.

Tuy nhiên, thực tế là tất cả phụ thuộc vào việc bạn đang làm gì. Nếu bạn đang tải một bài viết bằng ID số của nó, bạn không cần bất kỳ loại thoát nào, thậm chí ít PDO hơn. Bạn chỉ cần đảm bảo rằng ID thực sự là một số nguyên.

Từ góc độ thực tế hơn, quy tắc chung không phải là sử dụng các câu lệnh PDO/đã chuẩn bị, mà là sử dụng các hàm đúng, nghĩa là bạn phải sử dụng mysql_real_escape_string() thay vì addslashes() hoặc mysql_escape_string().

[5.] Một lập trình viên không bằng cách nào đó có thể xoay sở để vẫn làm hỏng việc này? Họ nên chú ý điều gì?

Tất nhiên! Nhưng đó không phải là "những gì cần chú ý" mà là "biết những gì bạn đang làm".

Bạn thấy, eval($_GET['code']) * là hoàn toàn hợp pháp khi được sử dụng ở đúng nơi (chẳng hạn như local PHP Test Runner).

Nếu bạn sử dụng ORM để chạy truy vấn có điều kiện, bạn đang nhập mã trực tiếp, do đó có thể có cơ hội bị tiêm SQL nếu bạn không làm đúng (phụ thuộc vào ORM trong câu hỏi). (Giả thuyết) Ví dụ:

// update() sets the value of a column given a condition
//
//                         .--escaping is automatic here
//                         |                           .--hypothetical SQL injection
//                         v                           v
Db()->update('name',$_GET['newname'])->where(' id = '.$_GET['id']);

(* Tôi chỉ có thể tưởng tượng vô số chuyên gia đập đầu họ về việc này)

13
Christian

Vào cuối ngày, việc thoát đầu vào phải được thực hiện để bảo vệ truy vấn của bạn dưới dạng SQL Injection. Các thư viện truy vấn được tham số hóa như PDO và ADODB sử dụng esc thoát , tất cả những gì họ làm là thực thi thực hành này theo cách hoàn toàn an toàn. Bằng cách hiểu ma thuật_quotes_gpc không [~ # ~] không [~ # ~] , đây là cách tiếp cận cơ bản cho vấn đề.

1) Việc trốn thoát có thể gặp vấn đề nếu bạn không hiểu việc mình đang làm. Loại vấn đề này vẫn có thể khai thác được nếu Magic_quotes_gpc được bật.

mysql_query("select * from users where id=".addslashes($_GET[id]));

Khai thác PoC: http: //localhost/vuln.php? Id = ngủ ( )

bản vá:

mysql_query("select * from users where id='".addslashes($_GET[id])."'");

Bài học: Bạn không cần dấu ngoặc kép để khai thác sql tiêm.

2) Hãy nói rằng bạn chỉ thoát dấu ngoặc kép:

mysql_query("select * from users where name='".htmlspecialchars($_GET[name],ENT_QUOTES)."' and id='".htmlspecialchars($_GET[id],ENT_QUOTES)."'");

Khai thác PoC: http: //localhost/vuln.php? Name = \& id = + hoặc + ngủ (30)/*

Bản vá:

mysql_query("select * from users where name='".addslashes($_GET[name])."' and id='".addslashes($_GET[id])."'");

Bài học : Dấu gạch chéo ngược là không kém phần nguy hiểm như dấu ngoặc kép.

3) Điều gì về mã hóa ngôn ngữ?

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".addslashes($_GET[name])."'");

Khai thác PoC: http: //localhost/vuln.php? Name =% bf% 27 = ngủ (30)/*

Bản vá:

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".mysql_real_escape_string($_GET[name])."'");

Kết luận:

Thoát là hoàn toàn cần thiết để ngăn chặn tiêm sql trong một ứng dụng. Trong PHP PDO và ADOB là các thư viện truy vấn được tham số hóa tuyệt vời để thực thi thoát khỏi đầu vào của người dùng. Vấn đề là nhiều lập trình viên không hiểu thoát là gì. Có một thư viện để thực thi chính sách bí mật này là phương pháp phòng vệ tốt nhất, bởi vì bạn không cần phải hiểu các quy tắc thoát.

9
rook

Về các chức năng thoát dành riêng cho DB. Có nhiều kịch bản theo đó SQL có thể xảy ra, mặc dù mysql_real_escape_opes () đã được sử dụng. GIỚI HẠN và ĐẶT HÀNG THEO thực sự là khó khăn!

Những ví dụ này dễ bị tấn công SQL:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
$sql = "SELECT userid, username FROM sql_injection_test LIMIT $offset, 10";

hoặc là

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
$sql = "SELECT userid, username FROM sql_injection_test ORDER BY `$order`";

Trong cả hai trường hợp, bạn không thể sử dụng 'để bảo vệ việc đóng gói.

nguồn : Lỗi SQL không mong đợi (Khi thoát không đủ) <- Đọc này

5
Cut Copy

Các bộ lọc có thể được bỏ qua và dữ liệu đi vào các câu lệnh SQL có thể đến từ nhiều nơi hơn là chỉ đầu vào của người dùng. Các điểm nhập vào nguồn/chìm chịu ảnh hưởng SQL có thể được lưu trữ (theo thứ tự cao hơn), như một ví dụ, nhưng rõ ràng các tham số HTTP GET và POST tham số từ các biểu mẫu HTML không phải là cách duy nhất của người dùng đầu vào.

Các truy vấn được tham số hóa không nhất thiết làm cho các câu lệnh SQL của bạn không bị tiêm. Chúng cũng yêu cầu liên kết biến, loại bỏ các hoạt động/nối chuỗi và tránh các vấn đề bảo mật nhất định với một phạm vi lớn các mệnh đề SQL.

Hầu hết các nhà phát triển cũng quên kiểm tra các thành phần bên thứ ba của họ và các phụ thuộc khác về các vấn đề tiêm SQL và đôi khi không nhận ra rằng các vùi này có thể làm cho mã của họ dễ bị tổn thương.

Điều tốt nhất cần làm là thuê một công ty tư vấn bảo mật ứng dụng để chuẩn bị (các) ứng dụng của bạn để sẵn sàng sản xuất và đào tạo (các) nhóm appdev của bạn về việc xây dựng các kiểm soát bảo mật ứng dụng vào quy trình và công nghệ phát triển của họ.

4
atdre

Để mở rộng câu trả lời của Hendrick. Thật dễ dàng để nghĩ real_escape_opes là một viên đạn ma thuật trong khi thực tế thì không. Tôi đã thấy mọi người sử dụng chức năng đó khi họ muốn sử dụng intval hoặc chuyển đầu vào thành một số nguyên thay thế. Bạn vẫn có thể bị tiêm nếu bạn sử dụng chuỗi thoát trong ngữ cảnh sai.

3
getahobby