SQL - Injection
Nếu bạn lấy thông tin đầu vào của người dùng thông qua một trang web và chèn nó vào cơ sở dữ liệu SQL, có khả năng là bạn đã để ngỏ cho mình một vấn đề bảo mật được gọi là SQL Injection. Chương này sẽ hướng dẫn bạn cách ngăn điều này xảy ra và giúp bạn bảo mật các tập lệnh và câu lệnh SQL của mình trong các tập lệnh phía máy chủ của bạn, chẳng hạn như Tập lệnh PERL.
Injection thường xảy ra khi bạn yêu cầu người dùng nhập vào, như tên của họ và thay vì tên họ cung cấp cho bạn một câu lệnh SQL mà bạn sẽ vô tình chạy trên cơ sở dữ liệu của mình. Không bao giờ tin tưởng vào dữ liệu do người dùng cung cấp, chỉ xử lý dữ liệu này sau khi xác nhận; như một quy luật, điều này được thực hiện bởiPattern Matching.
Trong ví dụ dưới đây, name bị hạn chế đối với các ký tự chữ và số cộng với dấu gạch dưới và độ dài từ 8 đến 20 ký tự (sửa đổi các quy tắc này nếu cần).
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
$result = mysql_query("SELECT * FROM CUSTOMERS
WHERE name = $matches[0]");
} else {
echo "user name not accepted";
}
Để chứng minh vấn đề, hãy xem đoạn trích này -
// supposed input
$name = "Qadir'; DELETE FROM CUSTOMERS;";
mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");
Lệnh gọi hàm phải lấy một bản ghi từ bảng CUSTOMERS trong đó cột tên khớp với tên do người dùng chỉ định. Trong những trường hợp bình thường,$namesẽ chỉ chứa các ký tự chữ và số và có thể là khoảng trắng, chẳng hạn như chuỗi ilia. Nhưng ở đây, bằng cách thêm một truy vấn hoàn toàn mới vào $ name, lệnh gọi đến cơ sở dữ liệu biến thành thảm họa; truy vấn DELETE được đưa vào sẽ xóa tất cả các bản ghi khỏi bảng CUSTOMERS.
May mắn thay, nếu bạn sử dụng MySQL, mysql_query()hàm không cho phép xếp chồng truy vấn hoặc thực thi nhiều truy vấn SQL trong một lệnh gọi hàm duy nhất. Nếu bạn cố gắng xếp chồng các truy vấn, cuộc gọi không thành công.
Tuy nhiên, các phần mở rộng cơ sở dữ liệu PHP khác, chẳng hạn như SQLite và PostgreSQL vui vẻ thực hiện các truy vấn xếp chồng lên nhau, thực hiện tất cả các truy vấn được cung cấp trong một chuỗi và tạo ra một vấn đề bảo mật nghiêm trọng.
Ngăn chặn SQL Injection
Bạn có thể xử lý tất cả các ký tự thoát một cách thông minh bằng các ngôn ngữ lập trình như PERL và PHP. Phần mở rộng MySQL cho PHP cung cấp chức năngmysql_real_escape_string() để thoát các ký tự đầu vào đặc biệt đối với MySQL.
if (get_magic_quotes_gpc()) {
$name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM CUSTOMERS WHERE name='{$name}'");
Các Quandary THÍCH
Để giải quyết yêu cầu LIKE, cơ chế thoát tùy chỉnh phải chuyển đổi các ký tự '%' và '_' do người dùng cung cấp thành các ký tự. Sử dụngaddcslashes(), một hàm cho phép bạn chỉ định một phạm vi ký tự để thoát.
$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
// $sub == \%str\_
mysql_query("SELECT * FROM messages
WHERE subject LIKE '{$sub}%'");