Trong bài học này, chúng ta sẽ cùng nhau tìm hiểu về một trong những lỗ hổng bảo mật phổ biến và nguy hiểm nhất khi làm việc với cơ sở dữ liệu – đó là SQL Injection. Đây là kiến thức cực kỳ quan trọng với bất kỳ lập trình viên nào, đặc biệt là khi bạn bắt đầu xây dựng ứng dụng thực tế có người dùng.
SQL Injection là gì?
SQL Injection (tiêm nhiễm câu lệnh SQL) xảy ra khi kẻ tấn công chèn mã SQL độc hại vào các input của người dùng (ví dụ: form đăng nhập, thanh tìm kiếm), từ đó thực thi các truy vấn không mong muốn tới cơ sở dữ liệu.
➡ Ví dụ: nếu bạn viết truy vấn như sau trong PHP:
$username = $_GET['username'];
$password = $_GET['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
Với truy vấn trên, nếu người dùng nhập:
username = admin
password = ' OR '1'='1
Thì câu lệnh SQL thực thi sẽ là:
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1'
Kết quả: điều kiện OR '1'='1'
luôn đúng ⇒ truy cập trái phép thành công.
Hậu quả của SQL Injection
- Truy cập vào hệ thống mà không cần đăng nhập
- Xem hoặc xóa dữ liệu trong bảng
- Lấy thông tin tài khoản, mật khẩu (nếu không mã hóa)
- Gây mất dữ liệu, chiếm quyền quản trị, ảnh hưởng nghiêm trọng đến bảo mật
Cách phòng tránh SQL Injection
Hãy luôn nhớ: đừng bao giờ tin vào dữ liệu người dùng nhập vào.
Dùng prepared statements (PDO hoặc MySQLi)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
Prepared Statement giúp tách phần câu lệnh và phần dữ liệu ⇒ dữ liệu dù chứa dấu nháy cũng không thể phá vỡ câu lệnh SQL.
Escape dữ liệu nếu cần
Nếu bạn không dùng prepared statement (không khuyến khích), bạn cần đảm bảo escape dữ liệu bằng mysqli_real_escape_string()
hoặc tương đương.
Giới hạn quyền truy cập của tài khoản database
- Không dùng tài khoản
root
- Chỉ cấp quyền cần thiết (chỉ
SELECT
,INSERT
nếu không cầnDELETE
)
Kiểm tra và validate dữ liệu đầu vào
- Dữ liệu email → kiểm tra đúng định dạng
- Dữ liệu số → ép kiểu và giới hạn giá trị
Thực hành: sửa lại truy vấn đăng nhập
Sai cách (dễ bị SQL Injection):
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
Đúng cách:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
Tổng kết
SQL Injection là lỗ hổng rất phổ biến và rất nguy hiểm, nhưng cũng rất dễ phòng tránh nếu bạn tuân thủ các nguyên tắc sau:
- Không bao giờ nối chuỗi trực tiếp trong câu lệnh SQL
- Luôn dùng prepared statements
- Kiểm tra, validate dữ liệu người dùng
- Hạn chế quyền truy cập CSDL
Trong các bài sau, bạn sẽ áp dụng kiến thức này để xây dựng một hệ thống an toàn, từ đăng nhập đến thao tác dữ liệu qua API.
👉 Tiếp theo, chúng ta sẽ học cách tạo Stored Procedure – một kỹ thuật nâng cao để tổ chức và tái sử dụng truy vấn SQL hiệu quả hơn.
Thảo luận