Database Security
SQL Injection là gì?
SQL Injection là gì, cơ chế tấn công (' OR 1=1 --), hậu quả, và hai cách phòng chống hiệu quả: Prepared Statements và Stored Procedures.
SQL Injection là gì?
SQL Injection là kỹ thuật tấn công mà kẻ tấn công chèn code SQL độc hại vào input của ứng dụng, khiến database thực thi các lệnh không mong muốn.
Đây là một trong những lỗ hổng bảo mật web phổ biến và nguy hiểm nhất (OWASP Top 10 nhiều năm liền).
1. Cơ chế tấn công
Giả sử ứng dụng xây dựng query đăng nhập như sau:
String query = "SELECT * FROM users WHERE username = '"
+ username + "' AND password = '" + password + "'";
Trường hợp bình thường (username = 'jane', password = 'pass123')
SELECT * FROM users WHERE username = 'jane' AND password = 'pass123'
Query hợp lệ, trả về user của jane nếu mật khẩu đúng.
Trường hợp tấn công (username = ' or 1=1 --, password = anything)
SELECT * FROM users WHERE username = '' or 1=1 --' AND password = 'anything'
Dấu -- là comment trong SQL → phần sau bị bỏ qua.
1=1 luôn TRUE → điều kiện WHERE luôn đúng → trả về TẤT CẢ user!
Các payload SQL Injection phổ biến
| Payload | Tác dụng |
|---|---|
' OR '1'='1 | Điều kiện luôn TRUE |
' OR 1=1 -- | Comment phần còn lại |
'; DROP TABLE users; -- | Xóa bảng users! |
' UNION SELECT username, password FROM admin -- | Lấy dữ liệu từ bảng khác |
2. Hậu quả của SQL Injection
- Bypass authentication: Đăng nhập không cần mật khẩu
- Data theft: Đánh cắp toàn bộ database
- Data destruction: Xóa bảng, schema
- Privilege escalation: Leo thang quyền admin
- Remote code execution: Trong một số cấu hình, chạy lệnh shell
3. Cách phòng chống — Prepared Statements
Prepared Statements (còn gọi là Parameterized Queries) tách hoàn toàn code SQL và dữ liệu user input. MySQL server xử lý SQL trước, dữ liệu được truyền vào sau dưới dạng tham số — không bao giờ được interpret như SQL code.
Python (mysql-connector)
cursor = db.cursor() query = "SELECT * FROM users WHERE username = %s AND password = SHA2(%s, 256)" cursor.execute(query, (username_input, password_input)) user = cursor.fetchone()
Java (JDBC)
String sql = "SELECT * FROM users WHERE username = ? AND password = SHA2(?, 256)"; PreparedStatement stmt = conn.prepareStatement(sql); stmt.setString(1, usernameInput); stmt.setString(2, passwordInput); ResultSet rs = stmt.executeQuery();
PHP (PDO)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :user AND password = SHA2(:pass, 256)");
$stmt->execute([':user' => $username, ':pass' => $password]);
$user = $stmt->fetch();
Dù kẻ tấn công nhập ' OR 1=1 -- vào username, server sẽ tìm kiếm username nào có giá trị đúng là ' OR 1=1 -- (gồm dấu nháy) — không có user nào như vậy → không đăng nhập được.
4. Cách phòng chống — Stored Procedures
Stored Procedure là đoạn code SQL được lưu sẵn trong database, nhận tham số an toàn:
DELIMITER //
CREATE PROCEDURE GetUser(IN p_username VARCHAR(100), IN p_password VARCHAR(50))
BEGIN
SELECT id, name FROM users
WHERE username = p_username
AND password = SHA2(p_password, 256);
END //
DELIMITER ;
CALL GetUser('jane', 'password123');
Input được truyền như tham số, không được nhúng vào SQL string → an toàn trước injection.
5. Các biện pháp bổ sung
- Input validation: Kiểm tra định dạng input (email phải có @, ID phải là số)
- Whitelist validation: Chỉ chấp nhận ký tự được phép
- Least privilege: Application user chỉ cần SELECT/INSERT/UPDATE, không cần DROP
- WAF (Web Application Firewall): Lọc request trước khi vào server
- Error handling: Không hiển thị lỗi SQL cho user — hacker có thể đọc cấu trúc database từ error message