What is SQL Injection?

SQL injection (SQLi) là một lỗ hổng thường xảy ra trong các ứng dụng có sử dụng SQL. Để khai thác lỗ hổng này, kẻ tấn công sẽ xây dựng một câu truy vấn và truyền (inject) nó vào các ô nhập liệu để server thực thi. Các câu truy vấn này có thể truy xuất đến các dữ liệu bí mật quan trọng hoặc thậm chí xóa cả cơ sở dữ liệu.

Minh họa:

Lỗ hổng SQL injection có thể xảy ra ở bất kỳ vị trí nào của câu truy vấn. Một vài vị trí phổ biến:

  • Mệnh đề WHERE ở trong các câu lệnh SELECT.
  • Mệnh đề WHERE ở trong các câu lệnh UPDATE.
  • Giá trị insert của câu lệnh INSERT.
  • Trong tên bảng hoặc tên cột của câu lệnh SELECT.
  • Trong mệnh đề ORDER BY của câu lệnh SELECT.

Lab: SQL Injection Vulnerability in WHERE Clause Allowing Retrieval of Hidden Data

Câu truy vấn giúp hiển thị các sản phẩm có category là Gifts mà đã được release.

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

Mục tiêu: lấy ra danh sách tất cả các sản phẩm kể cả những sản phẩm chưa được release.

Thêm payload sau vào cuối URL:

' OR 1=1--

Câu truy vấn trở thành:

SELECT * FROM products WHERE category = 'Gifts' OR 1=1-- AND released = 1

Lab: SQL Injection Vulnerability Allowing Login Bypass

Mục tiêu: đăng nhập với username là administrator mà không cần password.

Sử dụng payload sau ở ô username:

administrator'--

Exploiting SQL Injection

How to Prevent SQL Injection?

Có hai cách phổ biến để ngăn chặn SQL injection:

  1. Loại bỏ các ký tự nguy hiểm chẳng hạn như ', ; hoặc -- ở trong dữ liệu đầu vào.
  2. Sử dụng các câu lệnh được chuẩn bị trước (Prepared Statement) thay vì nối chuỗi để tạo thành câu query.

Đoạn code sau bị lỗ hổng SQL injection do sử dụng nối chuỗi để build câu query từ input của người dùng.

String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);

Sửa lại như sau:

PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();

Prepare statement chỉ có thể sử dụng cho các mệnh đề WHERE, INSERT hoặc UPDATE nhưng không thể sử dụng cho các phần khác của câu query chẳng hạn như tên cột, bảng hoặc mệnh đề ORDER BY. Ứng dụng cần sử dụng các kỹ thuật khác để phòng chống, chẳng hạn như sử dụng một danh sách các giá trị được phép (whitelist).

Resources