I - SQL Injection là gì?
- Sql injection (SQLi) là một kỹ thuật hack web bằng cách lợi dụng các lỗ hổng và truy vấn trong các kênh đầu vào của ứng dụng web để chèn thêm một đoạn SQL, làm sai lệch câu truy vấn ban đầu.
- mục đích nhằm khai thác, ăn cắp hay xáo trộn các thông tin, dữ liệu nằm trong phần cơ sở dữ liệu của web - nơi có những dữ liệu có giá trị và nhạy cảm nhất.
- Sql injection cho phép những kẻ tấn công website có khả năng thực hiện được các thao tác tương tự như một người quản trị web. Điều này không những gây cản trở sự hoạt động của ứng dụng mà thậm chí họ còn chiếm được quyền truy cập quản trị vào các máy chủ.
- các cuộc tấn công SQL Injection giúp hacker giả mạo danh tính, làm xáo trộn dữ liệu, làm mất hiệu lực giao dịch, thay đổi số dư, tiết lộ hoặc phá hủy dữ liệu trên hệ thống. Thậm chí, nó có thể khiến dữ liệu trở nên không khả dụng hoặc đạt được quyền quản trị của máy chủ cơ sở dữ liệu.
- Xem xét đoạn code PHP với cơ sở dữ liệu MySQL xử lý input chứa lỗ hổng SQL injection sau:
- Mã: Chọn tất cả
$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
mysql_query($query);
- dễ dàng nhận thấy đoạn code trên đang tiềm ẩn nguy cơ bị tấn công SQL injection do không có cơ chế ngăn chặn nào với các giá trị người dùng nhập vào câu lệnh truy vấn SQL
II - Các biện pháp ngăn chặn, phòng ngừa SQL Injection
1. Sử dụng hàm addslashes() kết hợp với hàm htmlspecialchars() trong PHP
- Hàm htmlspecialchars() sẽ chuyển các ký tự đặc biệt như &, <, >, ", ', và / thành các ký tự HTML
- Hàm addslashes() thêm dấu gạch chéo \ trước các ký tự đặc biệt như dấu nháy đơn ', dấu nháy kép ", dấu chấm phẩy ; và dấu gạch chéo \ trong chuỗi. Ví dụ khi người dùng nhập giá trị cho biến $username là ' OR 1=1 -- sau khi sử dụng hàm trên sẽ trở thành \' OR 1=1 --. Câu truy vấn khi đó: SELECT * FROM users WHERE username = '\' OR 1=1 --' trở nên an toàn
- Mã: Chọn tất cả
$username = addslashes(htmlspecialchars($_POST['username']));
$password = addslashes(htmlspecialchars($_POST['password']));
2. Sử dụng hàm mysql_real_escape_string() , mysqli_real_escape_string() , sqlite_escape_string() và các hàm tương tự
- Hàm mysqli_real_escape_string() là một hàm trong PHP dùng để ngăn chặn lỗ hổng SQL injection. Nó sẽ chuyển các ký tự đặc biệt trong chuỗi như ', ", ;, ... thành các ký tự hợp lệ để truy vấn cơ sở dữ liệu
- Mã: Chọn tất cả
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = mysqli_real_escape_string($conn, $_POST['password']);
3. Sử dụng PDO prepared statements
- PDO prepared statements sử dụng các câu lệnh SQL được thực thi trước đó để tránh các lỗ hổng bảo mật như SQL injection. Đồng thời nó cũng giúp tối ưu hóa các truy vấn và tăng tốc độ truy vấn.
- Mã: Chọn tất cả
// Tạo một đối tượng PDO:
$db = new PDO('mysql:host=localhost;dbname=myDatabase', $user, $pass);
// Tạo câu lệnh SQL cần thực thi:
$sql = "SELECT * FROM users WHERE username = :username";
//Tạo một đối tượng PDOStatement:
$stmt = $db->prepare($sql);
// Gán giá trị cho các tham số trong câu lệnh SQL:
$stmt->bindParam(':username', $username);
// Thực thi câu lệnh:
$stmt->execute();
// Lấy kết quả trả về:
$result = $stmt->fetchAll();
4. Kiểm tra kiểu dữ liệu đầu vào
- kiểm tra xem dữ liệu đầu vào có đúng với kiểu dữ liệu mong muốn hay không? PHP có nhiều hàm xác thực đầu vào, từ những hàm đơn giản nhất có trong Variable handling Functions và Character Type Functions ( ví dụ: is_numeric() , ctype_digit() ) cho đến các Biểu thức chính quy (Regular Expression)