- Hiểu vì sao string concatenation dẫn tới SQL Injection trong Flask + SQLite.
- Thực hành 3 nhóm tấn công phổ biến trên môi trường lab: authentication bypass, UNION-based SQLi, blind SQLi.
- So sánh trực tiếp bản
vulnerablevàpatchedđể thấy parameterized queries thay đổi hành vi ra sao. - Tự verify rằng cùng payload cũ không còn hiệu quả sau khi vá.
📖 Xem STUDENT_GUIDE và TEACHER_NOTES
sql-injection/
├── vulnerable/
│ ├── app.py
│ ├── database.py
│ └── templates/
├── patched/
│ ├── app.py
│ ├── database.py
│ └── templates/
├── exploits/
│ ├── exploit_login.py
│ ├── exploit_union.py
│ ├── exploit_blind.py
│ └── verify_patch.py
├── requirements.txt
└── README.md
Ghi chú:
vulnerable/giữ nguyên logic dễ tổn thương để phục vụ bài học tấn công.patched/dùng cùng schema và giao diện nhưng thay string concatenation bằng parameterized queries.exploits/chứa các script minh họa kỹ thuật tấn công và script xác nhận bản vá.
Trước tiên cài dependency từ thư mục gốc:
pip install -r requirements.txtcd vulnerable
python app.pyServer này dùng cho toàn bộ bài tập tấn công ban đầu.
Mở terminal khác:
cd exploits
python exploit_login.py
python exploit_union.py
python exploit_blind.pyMục tiêu:
- bypass login bằng payload comment / OR
- dump bảng
usersvàsecret_notesbằng UNION - xác nhận blind SQLi qua boolean-based và time-based
Mở terminal khác:
cd patched
python app.pyServer này chạy song song với vulnerable để học sinh so sánh trực tiếp before/after.
Mở terminal thứ ba:
cd exploits
python verify_patch.pyScript sẽ kiểm tra cả hai server:
http://localhost:5000để xác nhận bản vulnerable vẫn bị khai tháchttp://localhost:5001để xác nhận bản patched chặn cùng payload
Khi ứng dụng ghép trực tiếp input người dùng vào câu SQL, dữ liệu nhập vào không còn được xem là dữ liệu thuần nữa. Attacker có thể chèn thêm:
- toán tử logic như
OR,AND - comment SQL như
-- - mệnh đề
UNION SELECT - subquery cho blind SQLi
Kết quả là database thực thi logic do attacker điều khiển chứ không còn là truy vấn ban đầu của developer.
Parameterized query tách biệt:
- câu lệnh SQL
- giá trị đầu vào
Database nhận input như dữ liệu ràng buộc vào placeholder ?, nên chuỗi như ' OR 1=1-- chỉ còn là text bình thường thay vì cú pháp SQL có thể thực thi.
| Route | Vulnerable | Patched |
|---|---|---|
/login |
SELECT * FROM users WHERE username = ' + username + ' AND password = ' + password + ' |
SELECT * FROM users WHERE username=? AND password=? + execute(..., (username, password)) |
/search |
SELECT id, username, email, role FROM users WHERE username LIKE '% + keyword + %' |
SELECT id, username, email, role FROM users WHERE username LIKE ? + execute(..., (f"%{keyword}%",)) |
/ping |
SELECT id FROM users WHERE username = ' + keyword + ' |
SELECT id FROM users WHERE username = ? + execute(..., (keyword,)) |
Điểm cần quan sát:
- bản vulnerable thay đổi cú pháp SQL theo input
- bản patched giữ nguyên cú pháp SQL, chỉ thay giá trị tham số
- cùng payload nhưng hành vi server sẽ khác hoàn toàn
- Đã chạy được vulnerable server
- Đã bypass login thành công với payload
' OR 1=1-- - Đã dump được bảng
usersbằng UNION - Đã confirm Blind SQLi qua time-based
- Đã hiểu tại sao các payload hoạt động
- Đã chạy patched server và verify tất cả bị chặn
- Đã đọc và hiểu sự khác biệt code trước/sau patch