+3

SQL Injection

images.png

I) SQL Injection là gì?

SQL injection là một kỹ thuật cho phép những kẻ tấn công lợi dụng lỗ hổng của việc kiểm tra dữ liệu đầu vào trong các ứng dụng web và các thông báo lỗi của hệ quản trị cơ sở dữ liệu trả về để inject (tiêm vào) và thi hành các câu lệnh SQL bất hợp pháp. SQL injection có thể cho phép những kẻ tấn công thực hiện các thao tác, delete, insert, update,… trên cơ sở dữ liệu của ứng dụng, thậm chí là server mà ứng dụng đó đang chạy, lỗi này thường xảy ra trên các ứng dụng web có dữ liệu được quản lý bằng các hệ quản trị cơ sở dữ liệu như SQL Server, MySQL, Oracle, DB2, Sysbase...

II) Các kiểu tấn công thường gặp

1. Tấn công bằng mệnh đề luôn đúng

Những lỗi lập trình này thường xảy ra ở các chức năng tìm kiếm hoặc đăng nhập tài khoản.

Bạn có thể xem một đoạn code đơn gian bằng PHP mô tả một form đăng nhập hệ thống ở dưới đây:

Screenshot_2.png

đoạn code sau để kiểm tra thông tin login

if(isset($_POST['s'])) {
    $user = $_POST['user'];
    $pass = $_POST['password'];
    $sql = "select * from user where username = '$user' and password = '$pass'";
    echo "SQL: ". $sql;
    $re = mysql_query($sql);
    if(mysql_num_rows($re) == 0) {
        echo '<p style="color:red"> Login failed </p>' ;
    } else {
        echo '<p style="color:green"> Login Successful</p>';
    }
}

Trường hợp user đăng nhập: username = admin, pass = admin thì câu truy vấn sẽ là:

SQL: select * from user where username = 'admin' and password = 'admin'

Nếu biến "userName & password" được nhập chính xác theo một cách nào đó bởi người dùng ác ý, nó có thể trở thành một câu truy vấn SQL với mục đích khác .

Ví dụ, ta nhập vào giá trị của biến userName & pass như sau:

a' or '1'='1

Thì khi truy vấn, câu lệnh của chúng ta sẽ trở thành mệnh đề luôn đúng như dưới đây

SQL: select * from user where username = 'a' or '1'='1' and password = 'a' or '1'='1'

Dòng query trên sẽ select mọi thứ trong table user bất chấp username & password có bằng 'a' hay không. Bởi vì '1'='1' luôn luôn true, đó là lý do vì sao chúng ta có thể vượt qua màn hình đăng nhập một cách dễ dàng.

Screenshot_4.png

Screenshot_3.png

2. Tấn công phá hoại dữ liệu

Lỗi SQL injection dạng này 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 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.

sql = "select * from user where id = '$id' ";

Ta có thể nhận thấy một cách rõ ràng id - trường số (kiểu int). Tuy nhiên, người dùng , 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. Ví dụ, ta thiết lập giá trị của biến id là: 1;DROP TABLE users

Câu sql có thể được hiểu như sau:

SELECT * FROM user WHERE id=1;DROP TABLE user;

Dấu ( ; ) dùng để phân tách câu lệnh trong SQL, điều này đồng nghĩa với việc hacker có thể hành động thêm bất kì lệnh gì (như update,select,insert,delete..) vào trong câu lệnh trên, Như vậy sẽ rất nguy hiểm.

III. Phòng chống SQL Injection

Vậy để ngăn chặn hình thức tấn công SQL Injection chúng ta phải làm thế nào? Như các bạn đã thấy ở trên, Hacker lợi dụng sự lỏng lẻo về thiết kế của chương trình để tấn công, chúng ta cần có các biện pháp ngăn chặn:

* Dữ liệu nhập vào từ form giao diện người dùng phải được “làm sạch” trước khi tạo ra câu lệnh truy vấn.

* Đảm bảo dữ liệu đầu vào được lọc mà không ảnh hưởng đến cấu trúc của câu lệnh truy vấn.

* Phân quyền truy cập vào Database server với từng mức độ theo yêu cầu của từng chức năng.

* Ngoài ra để tránh các nguy cơ từ tấn công SQL Injection, nên chú ý loại bỏ bất kì thông tin kĩ thuật nào chứa trong thông điệp chuyển tới cho người dùng khi ứng dụng có lỗi. Các thông báo lỗi thông thường tiết lộ các chi tiết kĩ thuật có thể cho phép kẻ tấn công biết được điểm yếu của hệ thống.

1. Nếu dữ liệu kiểu INT

Khi bạn nhận dữ liệu ID trên URL thì cách tốt nhất ta nên ép kiểu, chuyển nó về kiểu số INT, sau đó chuyển về kiểu STRING.

$id = isset($_GET['id']) ? (string)(int)$_GET['id'] : false;

Hoặc dùng hàm str_replace để loại bỏ ký tự k phải là số, ngoài ra còn có 1 số hàm để kiểm tra kiểu dữ liệu như: is_numeric($var), is_int($var), is_integer($var)...

2. Nếu dữ liệu kiểu Chuỗi

Thiết lập độ dài tối đa cần thiết: MAX_LENGTH

Lọc bỏ ký tự nguy hiểm (bao gồm các meta characters trong DBMS), lọc bỏ các từ khóa như union, select, order, information_schema, insert, drop, load_file… (sử dụng các hàm như mysql_real_escape_string(), preg_replace()…)

Sử dụng hàm mysql_real_escape_string có nhiệm vụ loại bỏ ký tự đặc biệt, chuyển một chuỗi thành chuỗi query an toàn. Ví dụ:

mysql_real_escape_string("username"), mysql_real_escape_string("password"));

3. Viết lại đường dẫn

Viết lại đường dẫn của website có thể phòng được lỗi SQL Injection, vì hacker thường tìm lỗ hổng của website trên đường link hoặc trên form nhập liệu của người dùng, khi không nhìn thấy biến query thì hacker phải tìm cách khác để thử lỗi.

Kết luận

SQL injection luôn được đánh giá là một trong những lỗ hổng bảo mật web nguy hiểm nhất trong nhiều năm qua. Do đó, đối với những người lập trình web cần hiểu rõ nguyên nhân và cách khắc phục sao cho hiệu quả. Những người quản trị cần có những cấu hình cần thiết để trách nguy cơ và giảm thiểu tác hại trong trường hợp ứng dụng web có lỗi có thể khai thác SQL Injection.

Những năm trở lại đây thì xuất hiện nhiều Framwork nên lỗi SQL injection cũng được giảm, vì các Framwork đã hỗ trợ rất tốt việc chống lại hack SQL Injection này.

Link tham khảo: https://en.wikipedia.org/wiki/SQL_injection http://www.w3schools.com/sql/sql_injection.asp


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí