Hướng dẫn mysqli_query prevent sql injection - mysqli_query ngăn chặn tiêm sql
Bất kỳ truy vấn nào cũng có thể được tiêm cho dù nó được đọc hay viết, dai dẳng hay thoáng qua. Tiêm có thể được thực hiện bằng cách kết thúc một truy vấn và chạy một truy vấn riêng biệt (có thể với 1), điều này làm cho truy vấn dự định không liên quan. Show
Bất kỳ đầu vào nào cho một truy vấn từ một nguồn bên ngoài cho dù đó là từ người dùng hay thậm chí nội bộ nên được coi là một đối số cho truy vấn và một tham số trong bối cảnh của truy vấn. Bất kỳ tham số trong một truy vấn cần phải được tham số hóa. Điều này dẫn đến một truy vấn được tham số hóa đúng mà bạn có thể tạo một câu lệnh đã chuẩn bị từ và thực thi với các đối số. Ví dụ:
2 là một trình giữ chỗ cho một tham số. Sử dụng 1, bạn có thể tạo một câu lệnh đã chuẩn bị bằng 4, liên kết một biến (đối số) với tham số bằng cách sử dụng 5 và chạy truy vấn với 6. Bạn không cần phải vệ sinh đối số cả (thực tế là bất lợi khi làm như vậy). 1 làm điều đó cho bạn. Quá trình đầy đủ sẽ là:
Ngoài ra còn có một sự khác biệt quan trọng giữa truy vấn được tham số hóa và câu lệnh đã chuẩn bị. Tuyên bố này, trong khi chuẩn bị, không được tham số hóa và do đó dễ bị tiêm:
Để tóm tắt:
Bài viết này tập trung vào việc cung cấp hướng dẫn rõ ràng, đơn giản, có thể hành động để ngăn ngừa các lỗ hổng tiêm SQL trong các ứng dụng của bạn. Thật không may, các cuộc tấn công SQL là rất phổ biến, và điều này là do hai yếu tố: Các lỗ hổng SQL được giới thiệu khi các nhà phát triển phần mềm tạo các truy vấn cơ sở dữ liệu động được xây dựng với sự kết hợp chuỗi bao gồm đầu vào do người dùng cung cấp. Để tránh sai sót SQL là đơn giản. Các nhà phát triển cần phải: a) Ngừng viết các truy vấn động bằng cách ghép chuỗi; và/hoặc b) Ngăn chặn đầu vào do người dùng cung cấp có chứa SQL độc hại ảnh hưởng đến logic của truy vấn được thực hiện. Bài viết này cung cấp một tập hợp các kỹ thuật đơn giản để ngăn ngừa các lỗ hổng SQL bằng cách tránh hai vấn đề này. Những kỹ thuật này có thể được sử dụng với thực tế bất kỳ loại ngôn ngữ lập trình nào với bất kỳ loại cơ sở dữ liệu nào. Có các loại cơ sở dữ liệu khác, như cơ sở dữ liệu XML, có thể có vấn đề tương tự (ví dụ: tiêm XPath và XQuery) và các kỹ thuật này cũng có thể được sử dụng để bảo vệ chúng. Phòng thủ chính: Phòng thủ bổ sung: Ví dụ không an toàn: Lỗ hổng SQL thường trông như thế này: Ví dụ (Java) sau đây không an toàn và sẽ cho phép kẻ tấn công tiêm mã vào truy vấn sẽ được thực thi bởi cơ sở dữ liệu. Tham số "Tên tùy chỉnh" không được đánh giá đơn giản được thêm vào truy vấn cho phép kẻ tấn công tiêm bất kỳ mã SQL nào họ muốn. Thật không may, phương pháp này để truy cập cơ sở dữ liệu là quá phổ biến. Phòng thủ chính JoTùy chọn quốc phòng 1: Các câu lệnh được chuẩn bị (với các truy vấn được tham số hóa) ¶Việc sử dụng các câu lệnh đã chuẩn bị với ràng buộc biến (hay còn gọi là các truy vấn tham số hóa) là cách tất cả các nhà phát triển trước tiên nên được dạy cách viết các truy vấn cơ sở dữ liệu. Chúng đơn giản để viết, và dễ hiểu hơn các truy vấn động. Các truy vấn được tham số hóa buộc nhà phát triển trước tiên xác định tất cả các mã SQL, sau đó chuyển trong mỗi tham số cho truy vấn sau. Kiểu mã này cho phép cơ sở dữ liệu phân biệt giữa mã và dữ liệu, bất kể đầu vào người dùng nào được cung cấp. Các câu lệnh được chuẩn bị đảm bảo rằng kẻ tấn công không thể thay đổi mục đích của truy vấn, ngay cả khi các lệnh SQL được chèn bởi kẻ tấn công. Trong ví dụ an toàn dưới đây, nếu kẻ tấn công vào người dùng 8, truy vấn được tham số hóa sẽ không dễ bị tổn thương và thay vào đó sẽ tìm kiếm tên người dùng phù hợp với toàn bộ chuỗi 8.Khuyến nghị cụ thể về ngôn ngữ:
Trong những trường hợp hiếm hoi, các tuyên bố chuẩn bị có thể gây hại cho hiệu suất. Khi đối mặt với tình huống này, tốt nhất là a) xác thực mạnh tất cả dữ liệu hoặc b) thoát khỏi tất cả đầu vào được cung cấp của người dùng bằng cách sử dụng thói quen thoát khỏi nhà cung cấp cơ sở dữ liệu của bạn như được mô tả dưới đây, thay vì sử dụng câu lệnh đã chuẩn bị. Ví dụ về tuyên bố đã chuẩn bị Java an toàn: Ví dụ:: Ví dụ mã sau sử dụng 5, việc triển khai truy vấn được tham số hóa của Java, để thực hiện cùng một truy vấn cơ sở dữ liệu.
Safe C# .NET Chuẩn bị ví dụ:: Với .net, nó thậm chí còn đơn giản hơn. Việc tạo và thực hiện truy vấn không thay đổi. Tất cả những gì bạn phải làm chỉ đơn giản là chuyển các tham số cho truy vấn bằng cách sử dụng cuộc gọi 6 như được hiển thị ở đây.
Chúng tôi đã hiển thị các ví dụ trong Java và .NET nhưng thực tế tất cả các ngôn ngữ khác, bao gồm Fusion Fusion và Cổ điển ASP, hỗ trợ các giao diện truy vấn tham số hóa. Ngay cả các lớp trừu tượng SQL, như ngôn ngữ truy vấn ngủ đông (HQL) cũng có cùng loại vấn đề tiêm (mà chúng ta gọi là tiêm HQL). HQL cũng hỗ trợ các truy vấn được tham số hóa, vì vậy chúng tôi có thể tránh được vấn đề này: Ngôn ngữ truy vấn Hibernate (HQL) đã chuẩn bị (tham số được đặt tên) Ví dụ::
Ví dụ về các truy vấn được tham số hóa trong các ngôn ngữ khác, bao gồm Ruby, PHP, Fusion Fusion và Perl, hãy xem bảng gian lận tham số truy vấn hoặc trang web này. Các nhà phát triển có xu hướng thích cách tiếp cận câu lệnh đã chuẩn bị vì tất cả các mã SQL đều nằm trong ứng dụng. Điều này làm cho ứng dụng của bạn tương đối độc lập cơ sở dữ liệu. Tùy chọn quốc phòng 2: Thủ tục lưu trữ JoCác thủ tục được lưu trữ không phải lúc nào cũng an toàn với SQL tiêm. Tuy nhiên, một số cấu trúc lập trình thủ tục được lưu trữ tiêu chuẩn nhất định có tác dụng tương tự như việc sử dụng các truy vấn được tham số hóa khi được triển khai một cách an toàn, đó là tiêu chuẩn cho hầu hết các ngôn ngữ thủ tục được lưu trữ. Họ yêu cầu nhà phát triển chỉ xây dựng các câu lệnh SQL với các tham số được tự động tham số hóa trừ khi nhà phát triển thực hiện một cái gì đó phần lớn nằm ngoài định mức. Sự khác biệt giữa các câu lệnh đã chuẩn bị và các quy trình được lưu trữ là mã SQL cho quy trình được lưu trữ được xác định và lưu trữ trong chính cơ sở dữ liệu, và sau đó được gọi từ ứng dụng. Cả hai kỹ thuật này đều có hiệu quả tương tự trong việc ngăn ngừa tiêm SQL để tổ chức của bạn nên chọn cách tiếp cận nào có ý nghĩa nhất đối với bạn. Lưu ý: 'Được triển khai một cách an toàn' có nghĩa là quy trình được lưu trữ không bao gồm bất kỳ thế hệ SQL động không an toàn nào. Các nhà phát triển thường không tạo SQL động bên trong các thủ tục được lưu trữ. Tuy nhiên, nó có thể được thực hiện, nhưng nên tránh. Nếu không thể tránh được, quy trình được lưu trữ phải sử dụng xác thực đầu vào hoặc thoát thích hợp như được mô tả trong bài viết này để đảm bảo rằng tất cả người dùng được cung cấp đầu vào cho quy trình được lưu trữ không thể được sử dụng để đưa mã SQL vào truy vấn được tạo động. Kiểm toán viên luôn luôn tìm kiếm việc sử dụng SP_EXECUTE, EXECUTE hoặc EXEC trong các quy trình lưu trữ SQL Server. Hướng dẫn kiểm toán tương tự là cần thiết cho các chức năng tương tự cho các nhà cung cấp khác. Ngoài ra còn có một số trường hợp các thủ tục lưu trữ có thể làm tăng rủi ro. Ví dụ: trên MS SQL Server, bạn có 3 vai trò mặc định chính: 7, 8 và 9. Trước khi các thủ tục được lưu trữ được sử dụng, DBA sẽ cung cấp cho DB_DatareAder hoặc DB_Datawriter quyền cho người dùng của WebService, tùy thuộc vào các yêu cầu. Tuy nhiên, các thủ tục được lưu trữ yêu cầu quyền thực thi, một vai trò không có sẵn theo mặc định. Một số thiết lập trong đó quản lý người dùng đã được tập trung, nhưng được giới hạn trong 3 vai trò đó, khiến tất cả các ứng dụng web chạy theo quyền của DB_OWNER để các thủ tục được lưu trữ có thể hoạt động. Đương nhiên, điều đó có nghĩa là nếu một máy chủ bị vi phạm, kẻ tấn công có toàn quyền đối với cơ sở dữ liệu, nơi trước đây họ có thể chỉ có truy cập đọc.Ví dụ về thủ tục lưu trữ Java an toàn: Ví dụ:: Ví dụ mã sau sử dụng 0, việc triển khai giao diện thủ tục được lưu trữ của Java, để thực hiện cùng một truy vấn cơ sở dữ liệu. Quy trình được lưu trữ 1 sẽ phải được xác định trước trong cơ sở dữ liệu và thực hiện chức năng tương tự như truy vấn được xác định ở trên.
Ví dụ quy trình lưu trữ VB .NET an toàn:: Ví dụ mã sau sử dụng 2, triển khai của .NET của giao diện thủ tục được lưu trữ, để thực hiện cùng một truy vấn cơ sở dữ liệu. Quy trình được lưu trữ 1 sẽ phải được xác định trước trong cơ sở dữ liệu và thực hiện chức năng tương tự như truy vấn được xác định ở trên.
Tùy chọn quốc phòng 3: Xác thực đầu vào danh sách cho phépCác phần khác nhau của các truy vấn SQL không phải là các vị trí hợp pháp cho việc sử dụng các biến liên kết, chẳng hạn như tên của các bảng hoặc cột và chỉ báo thứ tự sắp xếp (ASC hoặc DESC). Trong các tình huống như vậy, xác thực đầu vào hoặc thiết kế lại truy vấn là phòng thủ phù hợp nhất. Đối với tên của các bảng hoặc cột, lý tưởng, các giá trị đó đến từ mã và không phải từ các tham số người dùng. Nhưng nếu các giá trị tham số người dùng được sử dụng để nhắm mục tiêu các tên bảng và tên cột khác nhau, thì các giá trị tham số sẽ được ánh xạ tới bảng hợp pháp/dự kiến hoặc tên cột để đảm bảo đầu vào người dùng không được đánh giá không kết thúc trong truy vấn. Xin lưu ý, đây là một triệu chứng của thiết kế kém và cần viết lại đầy đủ nếu thời gian cho phép. Dưới đây là một ví dụ về xác thực tên bảng.
4 sau đó có thể được nối trực tiếp vào truy vấn SQL vì giờ đây nó được biết đến là một trong những giá trị hợp pháp và mong đợi cho một tên bảng trong truy vấn này. Hãy nhớ rằng các chức năng xác thực bảng chung có thể dẫn đến mất dữ liệu khi tên bảng được sử dụng trong các truy vấn mà chúng không được mong đợi.Đối với một cái gì đó đơn giản như một thứ tự sắp xếp, sẽ là tốt nhất nếu người dùng cung cấp đầu vào được chuyển đổi thành boolean, và sau đó boolean được sử dụng để chọn giá trị an toàn để nối vào truy vấn. Đây là một nhu cầu rất chuẩn trong việc tạo truy vấn động. Ví dụ: 0Bất kỳ đầu vào người dùng thời gian nào cũng có thể được chuyển đổi thành không chuỗi, như một ngày, số, số, boolean, loại được liệt kê, v.v. an toàn để làm như vậy. Xác thực đầu vào cũng được khuyến nghị là một biện pháp bảo vệ thứ cấp trong mọi trường hợp, ngay cả khi sử dụng các biến liên kết như được thảo luận sau trong bài viết này. Nhiều kỹ thuật về cách thực hiện xác thực đầu vào mạnh được mô tả trong bảng cheat xác thực đầu vào. Tùy chọn phòng thủ 4: Thoát tất cả đầu vào do người dùng cung cấpKỹ thuật này chỉ nên được sử dụng như là phương sách cuối cùng, khi không có phương pháp nào ở trên là khả thi. Xác thực đầu vào có lẽ là một lựa chọn tốt hơn vì phương pháp này yếu so với các phòng thủ khác và chúng tôi không thể đảm bảo nó sẽ ngăn chặn tất cả các SQL tiêm trong tất cả các tình huống. Kỹ thuật này là để thoát khỏi đầu vào của người dùng trước khi đặt nó vào một truy vấn. Nó rất cụ thể trong cơ sở dữ liệu trong việc thực hiện của nó. Nó thường chỉ được khuyến nghị trang bị thêm mã di sản khi thực hiện xác thực đầu vào không hiệu quả về chi phí. Các ứng dụng được xây dựng từ đầu, hoặc các ứng dụng yêu cầu dung sai rủi ro thấp nên được xây dựng hoặc viết lại bằng cách sử dụng các truy vấn được tham số hóa, quy trình lưu trữ hoặc một số loại Mapper quan hệ đối tượng (ORM) xây dựng các truy vấn của bạn cho bạn. Kỹ thuật này hoạt động như thế này. Mỗi DBMS hỗ trợ một hoặc nhiều sơ đồ thoát khỏi ký tự cụ thể cho các loại truy vấn nhất định. Sau đó, nếu bạn thoát khỏi tất cả các đầu vào do người dùng cung cấp bằng cách sử dụng sơ đồ thoát thích hợp cho cơ sở dữ liệu bạn đang sử dụng, DBMS sẽ không nhầm lẫn đầu vào đó với mã SQL được viết bởi nhà phát triển, do đó tránh mọi lỗ hổng SQL có thể có. API bảo mật doanh nghiệp OWASP (ESAPI) là một thư viện kiểm soát bảo mật ứng dụng web miễn phí, miễn phí, giúp các lập trình viên dễ dàng viết các ứng dụng rủi ro thấp hơn. Các thư viện ESAPI được thiết kế để giúp các lập trình viên dễ dàng hơn trong việc trang bị lại bảo mật thành các ứng dụng hiện có. Các thư viện ESAPI cũng đóng vai trò là nền tảng vững chắc cho sự phát triển mới:
Để tìm Javadoc đặc biệt cho bộ mã hóa cơ sở dữ liệu, hãy nhấp vào lớp 5 ở phía bên trái. Có rất nhiều codec được thực hiện. Hai codec cụ thể của cơ sở dữ liệu là 6 và 7.Chỉ cần nhấp vào tên của họ trong 8 ở đầu trang codec giao diện.Tại thời điểm này, ESAPI hiện có bộ mã hóa cơ sở dữ liệu cho:
Bộ mã hóa cơ sở dữ liệu sắp tới cho:
Nếu bộ mã hóa cơ sở dữ liệu của bạn bị thiếu, xin vui lòng cho chúng tôi biết. Cơ sở dữ liệu Chi tiết thoát khỏi cơ sở dữ liệuNếu bạn muốn xây dựng các thói quen thoát ra của riêng mình, đây là các chi tiết thoát ra cho từng cơ sở dữ liệu mà chúng tôi đã phát triển bộ mã hóa ESAPI cho:
PostgresqlNếu bộ mã hóa cơ sở dữ liệu của bạn bị thiếu, xin vui lòng cho chúng tôi biết. Cơ sở dữ liệu Chi tiết thoát khỏi cơ sở dữ liệuNếu bạn muốn xây dựng các thói quen thoát ra của riêng mình, đây là các chi tiết thoát ra cho từng cơ sở dữ liệu mà chúng tôi đã phát triển bộ mã hóa ESAPI cho: 1Oracle Escaping¶ 2Thông tin này dựa trên thông tin nhân vật Escape Oracle. Thoát khỏi các truy vấn động Để sử dụng codec cơ sở dữ liệu ESAPI khá đơn giản. Một ví dụ về Oracle trông giống như: Vì vậy, nếu bạn có một truy vấn động hiện có được tạo trong mã của bạn sẽ đến Oracle trông như thế này: 4Bạn sẽ viết lại dòng đầu tiên trông như thế này: 3Và bây giờ nó sẽ an toàn với SQL Injection, bất kể đầu vào được cung cấp. Để có khả năng đọc mã tối đa, bạn cũng có thể xây dựng 9 của riêng bạn:Với loại giải pháp này, bạn chỉ cần kết thúc từng tham số do người dùng cung cấp được chuyển vào cuộc gọi 0 hoặc bất cứ điều gì bạn đặt tên cho cuộc gọi và bạn sẽ được thực hiện.Tắt thay thế ký tự Sử dụng 1 hoặc 2 để đảm bảo tắt thay thế ký tự tự động. Nếu thay thế ký tự này được bật, & ký tự sẽ được đối xử như tiền tố biến SQLPLUS có thể cho phép kẻ tấn công truy xuất dữ liệu riêng tư. 5Xem ở đây và ở đây để biết thêm thông tinThoát khỏi ký tự ký tự đại diện trong giống như mệnh đề Từ khóa String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
// …
} catch (OleDbException se) {
// error handling
}
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
// …
} catch (OleDbException se) {
// error handling
}
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
// …
} catch (OleDbException se) {
// error handling
}
|