Theo Wikipedia thì khái niệm SQL Injection được định nghĩa như sau :
SQL injection là một kỹ thuật điền vào những đoạn mã SQL bất hợp pháp cho phép khai thác một lỗ hổng bảo mật tồn tại trong cơ sở dữ liệu của một ứng dụng. Lỗ hổng bảo mật này có thể xuất hiện khi ứng dụng không có đoạn mã kiểm tra chuỗi ký tự thoát nhúng trong câu truy vấn SQL hoặc do sự định kiểu đầu vào không rõ ràng hay do lỗi cú pháp SQL của lập trình viên khiến cho một đoạn mã ngoại lai có thể được xử lý ngoài ý muốn. Nó là một ví dụ của sự rủi ro khi một ngôn ngữ lập trình hay ngôn ngữ kịch bản được nhúng trong một ngôn ngữ khác. Tấn công SQL injection còn có thể hiểu là hình thức tấn công chèn bất hợp pháp các đoạn mã SQL.
Hiểu một cách nôm na thì hacker sẽ chèn các câu truy vấn SQL để dễ dàng xâm nhập, thay đổi cấu trúc Database.
Lỗi SQL injection thường xảy ra do lập trình viên hay người dùng định nghĩa đầu vào dữ liệu không rõ ràng hoặc thiếu bước kiểm tra và lọc kiểu dữ liệu đầu vào. Điều này có thể xảy ra khi một trường số được sử dụng trong truy vấn SQL nhưng lập trình viên lại thiếu bước kiểm tra dữ liệu đầu vào để xác minh kiểu của dữ liệu mà người dùng nhập vào có phải là số hay không. Ví dụ như sau:
statement = "SELECT * FROM data WHERE id = " + a_variable + ";"
Ta có thể nhận thấy một cách rõ ràng ý định của tác giả đoạn mã trên là nhập vào một số tương ứng với trường id – trường số. Tuy nhiên, người dùng cuối, thay vì nhập vào một số, họ có thể nhập vào một chuỗi ký tự, và do vậy có thể trở thành một câu truy vấn SQL hoàn chỉnh mới mà bỏ qua ký tự thoát. Ví dụ, ta thiết lập giá trị của biến a_variable là:
1;DROP TABLE users
Khi đó, nó sẽ thực hiện thao tác xóa người dùng có id tương ứng khỏi cơ sở dữ liệu, vì câu truy vấn hoàn chỉnh đã được hiểu là:
SELECT * FROM DATA WHERE id=1;DROP TABLE users;
Tất cả các hàm trong WordPress được thiết kế chống SQL Injection được chia thành 2 trường hợp là input validation và query preparing.
Trong nhiều trường hợp, website của bạn có chứa form mà yêu cầu nhập thông tin từ phía người dùng thì luôn luôn phải kiểm tra các giá trị đó trước khi cập nhật vào database. Bao gồm các hàm sau :
+ esc_html($input): Hàm này sẽ mã hóa các chuỗi nhập vào, về chức năng thì nó tương tự như hàm htmlspecialchars() , chỉ khác ở chỗ là nếu hàm htmlspecialchars()được thực thi 2 lần thì hàm đó mã hóa 2 lần chuỗi nhập vào.
+ wp_kses($string, $allowed_html): Hàm này sẽ xóa những thẻ tag HTML không mong muốn được quy định trong biến $allowed_html.
+ esc_url($input): Hàm này sẽ kiểm tra đường dẫn người dùng nhập vào có đúng không.
VD: http://tanvietblog.info => Chấp nhận ; http://sadsadsa => Không chấp nhận.
+ is_email($email): Kiểm tra địa chỉ email có hợp lệ hay không.
+intval($input): Lấy giá trị số nguyên của biến nhập vào.
Còn rất nhiều hàm mà bạn có thể tham khảo trên trang Codex.
Trên đây là những hàm cơ bản để xác nhận, kiểm tra giá trị mà người dùng nhập vào nhưng chừng đó vẫn chưa đủ an toàn, bạn cần mã hóa thêm câu truy vấn trước khi thao tác với cơ sở dữ liệu.
Nếu dịch theo nghĩa tường minh thì Query preparing có nghĩa là “Chuẩn bị cho truy vấn” , đại ý là cần đảm bảo rằng dữ liệu chèn vào database là dữ liệu “sạch”. Điều này được thực hiện dễ dàng với 2 hàm trong WordPress là esc_sql($query) hoặc $wpdb->escape($query).
Trong đó lớp $wpdb chịu trách nhiệm thao tác với cơ sở dữ liệu bao gồm thêm, sửa, xóa…Các bạn có thể tìm hiểu thêm $wpdb tại đây.
Về cơ bản thì 2 hàm trên tương tự như hàm addslashes()trong PHP, tức là nó sẽ chèn dấu ‘\’ vào câu truy vấn.
Sau đây tôi có một câu lệnh như sau :
$query = $wpdb->escape("SELECT * from $wpdb->posts WHERE post_id=$id");
Như bạn thấy, biến $id được truyền giá trị tức tiếp vào trường post_id, nếu biến $id đã được kiểm tra với các hàm input validation mà tôi đã trình bày ở trên cộng với việc sử dụng hàm $wpdb->escape thì câu lệnh này xem là an toàn. Nhưng đôi lúc bạn cũng nên kiểm tra kiểu dữ liệu đầu vào thay vì gán trực tiếp giá trị . Đó là lúc chúng ta cần dùng đến hàm $wpdb->prepare .
Ví dụ : Lấy nội dung comment của một người dùng
$wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID=%d and comment_author_email=%s", $id,$email));
Ở câu truy vấn trên, thay vì lấy giá trị trực tiếp gán vào trường comment_ID và comment_author_email thì chúng ta nên dùng %d thay cho biến $id và %s cho biến $email.
Như vậy, kết hợp cả 2 trường hợp input validation và query preparing thì chúng ta sẽ có câu lệnh truy vấn chống SQL Injection tương đối hoàn hảo.
$data = esc_html($_POST['data']);
$result = $wpdb->get_results($wpdb->prepare("SELECT * FROM table WHERE field=%s", $data));
» Tin mới nhất:
» Các tin khác: