SQL Injection là gì? Cách Phòng Chống Tấn Công SQL Injection Chuyên mục Bài Viết Hay 2024-05-13 24 Lượt xem 21 Lượt thích 0 Bình luận
SQL Injection là một loại lỗ hổng bảo mật web xảy ra khi một kẻ tấn công có thể chèn hoặc "tiêm" các lệnh SQL độc hại vào một truy vấn SQL hợp lệ. Điều này có thể cho phép kẻ tấn công thực hiện các hành động không mong muốn trên cơ sở dữ liệu của ứng dụng, chẳng hạn như truy cập dữ liệu nhạy cảm, thay đổi hoặc xóa dữ liệu, và thậm chí thực hiện các lệnh quản trị.
Ví dụ
Ví dụ 1 về SQL Injection
Giả sử bạn có một ứng dụng web với một form đăng nhập đơn giản. Người dùng nhập tên người dùng và mật khẩu, và ứng dụng thực hiện truy vấn SQL sau để xác thực người dùng:
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $sql);
Nếu người dùng nhập ' OR '1'='1 vào trường tên người dùng và bất kỳ thứ gì vào trường mật khẩu, truy vấn SQL sẽ trở thành:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '';
Phần ' OR '1'='1' luôn luôn đúng, vì vậy truy vấn sẽ trả về tất cả các hàng trong bảng users, cho phép kẻ tấn công đăng nhập mà không cần biết mật khẩu thực sự.
Ví dụ 2 về SQL Injection:
$name = "s2sontech'; DELETE FROM SINHVIEN; -- ";
mysql_query("SELECT * FROM CUSTOMERS WHERE name='{$name}' ");
Phân tích lệnh SQL được tạo ra
Khi giá trị của $name là "s2sontech'; DELETE FROM SINHVIEN; -- ", truy vấn SQL sẽ trở thành:
SELECT * FROM CUSTOMERS WHERE name='s2sontech'; DELETE FROM SINHVIEN; -- ';
Đoạn mã trên sẽ được phân tích như sau:
- SELECT * FROM CUSTOMERS WHERE name='s2sontech': Tìm tất cả các hàng trong bảng CUSTOMERS có cột name là 's2sontech'.
- DELETE FROM SINHVIEN: Xóa tất cả các hàng trong bảng SINHVIEN.
- -- ': Bỏ qua phần còn lại của câu lệnh SQL.
Cách ngăn ngừa
Cách ngăn ngừa SQL Injection ở ví dụ 1:
- Sử dụng Prepared Statements (Câu lệnh chuẩn bị sẵn)
Prepared Statements tách biệt dữ liệu đầu vào của người dùng khỏi mã SQL, giúp ngăn ngừa SQL Injection.
Lý do Prepared Statements ngăn ngừa SQL Injection
-
Tách biệt mã SQL và dữ liệu đầu vào:
- Khi bạn sử dụng Prepared Statements, bạn đang tách biệt phần cấu trúc của câu lệnh SQL khỏi dữ liệu đầu vào. Điều này có nghĩa là các dữ liệu đầu vào sẽ không bao giờ được coi là một phần của mã SQL.
-
Xử lý dữ liệu đầu vào an toàn:
- PDO sẽ tự động thoát (escape) các ký tự đặc biệt trong dữ liệu đầu vào. Điều này ngăn chặn việc chèn các đoạn mã độc hại vào câu lệnh SQL.
-
Cố định cấu trúc câu lệnh SQL:
- Câu lệnh SQL được xác định trước (prepared) và không thay đổi dựa trên dữ liệu đầu vào. Do đó, không có cách nào để dữ liệu đầu vào thay đổi mục đích của câu lệnh SQL ban đầu.
Ví dụ với MySQLi:
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();
Ví dụ với PDO:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();
$result = $stmt->fetch();
- Sử dụng ORM (Object-Relational Mapping)
Sử dụng ORM như Eloquent (Laravel) hoặc Doctrine (Symfony) để tự động hóa việc tạo các truy vấn an toàn.
Ví dụ với Eloquent (Laravel):
$user = User::where('username', $username)->where('password', $password)->first();
- Escaping đầu vào người dùng
Sử dụng các hàm thoát ký tự (escaping functions) để xử lý dữ liệu đầu vào của người dùng.
Ví dụ với MySQLi:
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = mysqli_real_escape_string($conn, $_POST['password']);
Ví dụ với PDO:
PDO tự động thoát ký tự khi sử dụng prepared statements.
- Sử dụng các thư viện bảo mật
Sử dụng các thư viện hoặc framework đã được chứng minh là an toàn để xử lý các truy vấn SQL.
Bằng cách sử dụng các biện pháp trên, bạn có thể giảm thiểu nguy cơ SQL Injection và bảo vệ cơ sở dữ liệu của mình khỏi các tấn công .
Cách ngăn ngừa SQL Injection ở ví dụ 2:
Để ngăn ngừa SQL Injection, bạn nên sử dụng Prepared Statements hoặc các thư viện cung cấp các hàm an toàn để thực thi các truy vấn SQL. Dưới đây là cách làm điều đó.
Sử dụng MySQLi với Prepared Statements
// Kết nối đến cơ sở dữ liệu
$conn = new mysqli($servername, $username, $password, $dbname);
// Kiểm tra kết nối
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Chuẩn bị câu lệnh
$stmt = $conn->prepare("SELECT * FROM CUSTOMERS WHERE name = ?");
$stmt->bind_param("s", $name);
// Thực thi câu lệnh
$stmt->execute();
// Lấy kết quả
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo $row['name'];
}
// Đóng câu lệnh và kết nối
$stmt->close();
$conn->close();
Sử dụng PDO với Prepared Statements
// Kết nối đến cơ sở dữ liệu
try {
$pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Chuẩn bị câu lệnh
$stmt = $pdo->prepare("SELECT * FROM CUSTOMERS WHERE name = :name");
$stmt->bindParam(':name', $name);
// Thực thi câu lệnh
$stmt->execute();
// Lấy kết quả
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['name'];
}
} catch(PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
// Đóng kết nối
$pdo = null;
Kết luận
Việc sử dụng Prepared Statements giúp ngăn chặn SQL Injection bằng cách đảm bảo rằng dữ liệu đầu vào của người dùng được xử lý đúng cách và không thể thực thi như một phần của câu lệnh SQL. Điều này giúp bảo vệ ứng dụng của bạn khỏi các cuộc tấn công tiêm nhiễm SQL và bảo vệ cơ sở dữ liệu của bạn khỏi bị truy cập hoặc thay đổi trái phép.
Bình luận (0)