Đăng nhập

Bài 31: SQL Injection – Hiểu và Phòng Tránh

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ần DELETE)

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

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Đăng ký nhận tin mới

Nhận bài học, tài nguyên và cơ hội việc làm qua email hàng tuần.

Chúng tôi cam kết không spam. Bạn có thể hủy bất cứ lúc nào.