Một cuộc thi "cún đẹp" dành riêng cho các bạn cún loài Chihuahua. Đặc điểm của loài Chihuahua là luôn sủa ăng ẳng, vì vậy ban tổ chức "cẩn thận" thông báo: Chỉ cho phép các cún Chihuahua và các cún luôn sủa ăng ẳng được vào cổng.
Một chú chó German Shepherd to lớn, không có "giấy mời" vẫn nghênh ngang vào cổng chỉ vì chú có một tật ít ai ngờ đó là sủa ăng ẳng suốt ngày! Chú là "khách không mời"! Và thông báo của Ban Tổ Chức có một "lỗ hổng". Quay lại với lập trình, bạn mới làm website đầu tiên.
Có form login.
Nhìn rất chuyên nghiệp.
Username
Password
[ Login ]
Bạn "rung đùi" tự tin nghĩ:
"Chỉ có tôi biết tài khoản admin thôi."
Nhưng vài phút sau.
Hacker đăng nhập được.
Trong khi:
- Không biết password
- Không biết admin là ai
- Không hack server
Lính mới sẽ nghĩ:
"Chuyện quái gì đang xảy ra vậy? PHP phản chủ rồi à?"
SQL Injection là gì?
SQL Injection là một lỗ hổng bảo mật xảy ra khi dữ liệu người dùng nhập vào được ghép trực tiếp vào câu lệnh SQL.
Kẻ tấn công có thể:
Đăng nhập trái phép
Xem dữ liệu
Xóa dữ liệu
Thậm chí chiếm quyền quản trị
Đây là một trong những lỗ hổng nổi tiếng nhất trong lịch sử web.
Ví dụ thực tế
Bạn tới một khu chung cư.
Bảo vệ hỏi:
"Anh ở căn hộ nào?"
Bạn trả lời:
"Tôi ở căn hộ 101."
Bảo vệ kiểm tra.
Nếu đúng.
Cho vào.
Nhưng có một người khác trả lời:
"Tôi ở căn hộ 101 hoặc bất kỳ căn hộ nào cũng được."
Và bảo vệ vẫn cho vào.
Đó chính là tinh thần của SQL Injection.
Ví dụ đau lòng
Form Login:
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users
WHERE username='$username'
AND password='$password'";Nhìn rất bình thường.
Người dùng nhập:
admin
123456
PHP tạo:
SELECT * FROM users
WHERE username='admin'
AND password='123456'Không có vấn đề gì.
Hacker nhập gì?
Username:
admin
Password:
' OR '1'='1
Lúc này câu SQL trở thành:
SELECT * FROM users
WHERE username='admin'
AND password='' OR '1'='1'Nhìn kỹ:
'1'='1'
luôn đúng.
Database:
"Ờ cũng hợp lý. Duyệt!"
Và hacker vào được.
Vì sao chuyện này xảy ra?
Nguyên nhân nằm ở đây:
$sql = "SELECT ...
WHERE username='$username'";Bạn đang cho phép người dùng:
Viết dữ liệu
↓
Chen vào SQL
Database không phân biệt được:
- Đâu là dữ liệu
- Đâu là câu lệnh
Đó chính là nguồn gốc của SQL Injection.
Một ví dụ cực kỳ nguy hiểm
Code:
$id = $_GET['id'];
$sql = "DELETE FROM users
WHERE id=$id";Người dùng bình thường:
?id=5
SQL:
DELETE FROM users
WHERE id=5Ổn.
Nhưng hacker:
?id=5 OR 1=1SQL:
DELETE FROM users
WHERE id=5 OR 1=1
Vì:
1=1
luôn đúng.
Kết quả:
Xóa toàn bộ users
Lính mới...ngơ ngác:
"Em chỉ muốn xóa user số 5 thôi mà..."
Một sự thật thú vị
Ngày xửa, ngày xưa.
SQL Injection nguy hiểm tới mức:
- Website ngân hàng
- Website chính phủ
- Website thương mại điện tử
đều từng dính.
Nó từng là "ông vua" của các lỗ hổng web.
Sai lầm phổ biến của lính mới
Nghĩ rằng:
- Website nhỏ
- Không ai hack
Thực tế:
- Bot tự động quét Internet 24/7.
- Không cần nổi tiếng.
- Không cần nhiều traffic.
- Vẫn có thể bị thử SQL Injection.
Chỉ kiểm tra giao diện
Lính mới thường test theo cách rất đơn giản:
admin
123456
Đăng nhập được.
Và nghĩ:
Hoàn thành
Trong khi hacker lại nhập:
' OR '1'='1
Dấu hiệu code dễ bị SQL Injection
Ví dụ:
$sql = "SELECT * FROM users
WHERE username='$username'";Hoặc:
$sql = "SELECT * FROM products
WHERE id=".$_GET['id'];Hoặc:
$sql = "DELETE FROM users
WHERE id=$id";Nếu thấy:
Ghép chuỗi trực tiếp
thì nên cảnh giác.
Tập tành làm web
Trong giai đoạn đầu khi còn đang "vọc" những thứ miễn phí để "nâng cao tay nghề". Rất có thể bạn nghĩ: Host miễn phí nên bị hack.
Không đâu, "làm ơn" đừng nghĩ vậy.
SQL Injection xảy ra ở:
Code
chứ không phải:
Hosting
Dù:
- InfinityFree
- Shared Hosting
- VPS
- Dedicated Server
thì code sai vẫn nguy hiểm như nhau.
Debug kiểu dev "xịn sò"
1. Echo câu SQL
Ví dụ:
echo $sql;
Xem dữ liệu người dùng đã chèn vào gì.
2. Test ký tự đặc biệt
Ví dụ:
'
"
--
;
Website có lỗi không?
3. Không ghép chuỗi trực tiếp
Đây là nguyên tắc quan trọng nhất.
Checklist chuẩn không cần chỉnh
- Không ghép SQL bằng dữ liệu người dùng
- Kiểm tra mọi GET/POST
- Test ký tự '
- Test ký tự "
- Test URL
- Không chủ quan vì website nhỏ
- Hiểu Prepared Statement
FAQ nhanh
SQL Injection có còn tồn tại không?
Có. Rất nhiều website nhỏ vẫn mắc.
Chỉ PHP mới bị SQL Injection?
Không. Nhiều ngôn ngữ đều có thể gặp.
SQL Injection có phải do MySQL lỗi?
Không. Thường do cách lập trình.
Website cá nhân có cần quan tâm không?
Có. Đặc biệt nếu có:
- Login
- Form
- Database
Bạn có thể cũng đang gặp
Login đúng password nhưng vẫn fail
Tổng kết
SQL Injection xảy ra khi:
Dữ liệu người dùng được ghép trực tiếp vào câu SQL.
Kết quả có thể từ:
Đăng nhập trái phép
cho tới:
Mất toàn bộ dữ liệu
Điều đáng sợ nhất là:
- Website vẫn chạy bình thường.
- Không báo lỗi.
- Không có warning.
- Không có Fatal Error.
Nhưng cánh cửa sau đã mở sẵn cho hacker từ lâu.