Nếu bạn nhận User Input thông qua một Webpage và chèn nó vào trong một SQLite Database, thì tình cờ, bạn đã mở rộng cửa bảo mật ra bên ngoài, mà được biết đến với tên gọi là SQL Injection. Chương này sẽ hướng dẫn bạn cách ngăn cản tình huống này xảy ra và giúp bạn bảo vệ Script của bạn và các lệnh SQLite của bạn.
Injection thường xảy ra khi bạn yêu cầu input từ một người dùng, như tên của họ, và thay vì cung cấp tên, họ cung cấp cho bạn một lệnh SQLite mà bạn sẽ chạy trên Database của mình mà không hay biết.
Đừng bao giờ tin vào dữ liệu được cung cấp bởi người dùng, xử lý dữ liệu này, và như một qui tắc, điều này được thực hiện bởi Pattern Matching (so khớp mẫu).
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)){
$db = new SQLiteDatabase('filename');
$result = @$db->query("SELECT * FROM users WHERE username=$matches[0]");
}else{
echo "username not accepted";
}
Để minh họa vấn đề, bạn xem phần trích sau:
$name = "Qadir'; DELETE FROM users;";
@$db->query("SELECT * FROM users WHERE username='{$name}'");
Lời gọi hàm được xem như để lấy một bản ghi từ bảng users, với cột name so khớp với name đã được xác định bởi người dùng. Thông thường, $name sẽ chỉ chứa các ký tự chữ-số và có thể có khoảng trống. Nhưng ở đây, bằng việc phụ thêm một truy vấn hoàn toàn mới tới $name, lời gọi tới Database sẽ gây ra vấn đề lớn: truy vấn DELETE bị tiêm vào sẽ xóa tất cả bản ghi từ bảng users.
Có một số Database không cho phép Query Stacking hoặc thực thi nhiều truy vấn trong một lời gọi hàm đơn. Nếu bạn nỗ lực để thực hiện nhiều truy vấn, lời gọi hàm sẽ thất bại. Tuy nhiên, với SQLite và PostgreSQL, lại cho thực hiện nhiều truy vấn, thực thi tất cả truy vấn được cung cấp trong một chuỗi và điều này tạo ra một vấn đề rất nghiêm trọng.
Ngăn cản SQL Injection
Bạn có thể xử lý tất cả Escape Character một cách khéo léo trong các ngôn ngữ Scripting như PERL và PHP. Ngôn ngữ lập trình PHP cung cấp hàm sqlite_escape_string() để tránh các ký tự được nhập vào mà có ý nghĩa đặc biệt với SQLite.
if (get_magic_quotes_gpc())
{
$name = sqlite_escape_string($name);
}
$result = @$db->query("SELECT * FROM users WHERE username='{$name}'");
Mặc dù việc mã hóa này đảm bảo an toàn khi chèn dữ liệu, nó sẽ trả lại các so sánh thuần text và mệnh đề LIKE trong các truy vấn của bạn không thích hợp cho các cột mà chứa dữ liệu nhị phân.
Bạn nhớ rằng hàm addcslashes() không nên được sử dụng để trích dẫn các chuỗi của bạn cho các truy vấn SQLite. Nó sẽ tạo ra các kết quả kì quặc khi lấy dữ liệu của bạn.