Kỹ thuật tấn công SQL Injection và cách phòng chống trong PHP
NỘI DUNG BÀI VIẾT
Ở bài trước chúng ta đã được tìm hiểu cách phòng chống CSRF, vậy thì trong bài này ta sẽ tìm hiểu thêm một kỹ thuật khác cũng rất hay sử dụng để tấn công vào những website của những tay nghề thiếu kinh nghiệm lập trình, đó là kỹ thuật tấn công SQL Injection.
1. SQL Injection là gì?
SQL Injection là một kỹ thuật lợi dụng những lỗ hổng về câu truy vấn lấy dữ liệu của những website không an toàn trên web, đây là một kỹ thuật tấn công rất phổ biến và sự thành công của nó cũng tương đối cao. Tuy nhiên vào những năm trở lại đây thì xuất hiện nhiều Framwork nên nó giảm hẳn, vì các FW đã hỗ trợ rất tốt việc chống lại hack SQL Injection này.
Chắc hẳn các bạn đã biết mô hình hoạt động của website rồi nhỉ? Khi một request được gửi từ client thì ngôn ngữ SERVER như PHP sẽ lấy các thông tin từ request đó. Nhưng bản thân nó không hề phát hiện ra những thông tin đó có chứa những câu SQL độc, vì thế công việc này ta phải đổ trách nhiệm tới kinh nghiệm của lập trình viên.
Ví dụ: Giả sử tôi có một trang đăng nhập với hai thông tin là tên đăng nhập và mật khẩu.
Và đoạn code xử lý tấn công sql injection của tôi có dạng như sau:
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "select count(*) from user where username = '$username' AND password = '$password'";
Code language: PHP (php)
Trường hợp 1: Bây giờ tôi nhập username = thehalfheart
và password = matkhau
thì câu truy vấn sẽ là:
select count(*) from user where username = 'thehalfheart AND password = 'matkhau'
Trường hợp 2: Bây giờ tôi nhập username = somename
và password = something' OR '1
. Như vậy câu sql sẽ là:
SELECT * FROM cms_user WHERE user_username = 'thehalfheart' AND user_password = 'something' OR '1'
Chạy câu truy vấn này lên thì kết quả nó trả về là danh sách user nên nếu code cùi cùi thì login được luôn.
Trên đây là một ví dụ điển hình thôi, chứ thực tế thì hacker còn rất nhiều mưu mẹo khác. Tuy nhiên chung quy lại với kỹ thuật tấn công SQL Injection ta vẫn có thể không chế được nó.
2. Phòng chống SQL Injection
Với kinh nghiệm của mình thì thật sự chưa phân tích sâu vào kỹ thuật này, tuy nhiên mình cũng biết chút ít kinh nghiệm để có thể chống lại kỹ thuật này.
2.1. Nhận dữ liệu kiểu INT
Khi bạn nhận dữ liệu ID trên URL thì cách tốt nhất bạn nên ép kiểu, chuyển nó về kiểu số INT, sau đó chuyển về kiểu STRING (nếu cần thiết).
Ví dụ: tôi có url như sau: domain.com/detail.php?id=12
$id = isset($_GET['id']) ? (string)(int)$_GET['id'] : false;
Code language: PHP (php)
Như vậy thì cho dù ta nhập vào kỳ tự gì đi nữa đều sẽ bị clear ra khỏi hết. Hoặc ta có thể dùng cách dước bằng cách dùng hàm preg_replace trong PHP để xóa đi những ký tự không phải là chữ số.
$id = isset($_GET['id']) ? $_GET['id'] : false;
$id = str_replace('/[^0-9]/', '', $id);
Code language: PHP (php)
Rất đơn giản, tuy nhiên mình khuyến khích nên dùng ép kiểu trong PHP, vì nó đơn giản.
2.2 Viết lại đường dẫn có thể chống SQL Injection
Vấn đề này có vẻ hơi lạ nhưng bản thân mình thấy rất đúng. Khi bạn viết lại đường dẫn dù trên hệ thống route của FW hay dù trên file .htaccess thì hãy fix chính xác đoạn mã Regular Expression (Tham khảo Regular Expression căn bản).
Ví dụ: Tôi có đường dẫn sau khi rewirte là như sau: domain.com/hoc-lap-trinh-mien-phi-tai-freetuts.html thì đoạn Regex tôi sẽ viết là:
/([a-zA-Z0-9-]+)/([a-zA-Z0-9-]+)\.html/
. Thay vì như vậy thì tôi sẽ viết chính xác /([a-zA-Z0-9-]+)/([0-9])\.html/
thì sẽ tốt hơn. Và đừng quên là cũng ẩn đi đường link gốc của nó nhé.
2.3 Sử dụng hàm sprintf và mysql_real_escape_string để xác định kiểu dữ liệu cho câu truy vấn.
Như bạn biết hàm sprintf gồm có hai tham số trở lên, tham số thứ nhất là chuỗi và trong đó có chứa một đoạn Regex để thay thế, tham số thứ 2 trở đi là các giá trị sẽ được thay thế tương ứng. Giá trị ráp vào sẽ được convert phù hợp rồi mới rap vào
Ví dụ:
$webname = 'freetuts.net';
$title = 'học lập trình miễn phí';
echo sprintf('Website %s laf website %s', $webname, $title);
Code language: PHP (php)
Kết quả in ra là: Website freetuts.net là website học lập trình miễn phí.
Nếu bạn chưa biết về hàm sprintf thì vào link này đọc nhé.
Như bạn biết hàm mysql_real_escape_string có nhiệm vụ sẽ chuyển một chuỗi thành chuỗi query an toàn, nên ta sẽ kết hợp nó để gán vào câu truy vấn. Ví dụ:
$sql = "SELECT * FROM member WHERE username = '%s' AND password = '%s'";
echo sprintf($sql, mysql_real_escape_string("thehalfheart"), mysql_real_escape_string("matkhau"));
Code language: PHP (php)
Kết quả là: SELECT * FROM member WHERE username = ‘thehalfheart’ AND password = ‘matkhau’.
3. Lời kết
Thật sự thì kỹ thuật này rất nhiều và dài, kiến thức của mình chỉ mang tầm căn bản nên mình chỉ share được căn bản. Nếu bạn muốn nâng cao thì có thể đọc thêm tài liệu trên mạng, chủ yếu là tiếng anh. Tuy nhiên thật sự khi đi làm bạn nên sử dụng Framwork, vì FW đa hỗ trợ rất tốt những kiểu tấn công website thông dụng hiện nay rồi, bản thân chúng ta không thể nào tìm hiểu sâu được.
Nguồn: https://freetuts.net/ky-thuat-tan-cong-sql-injection-va-cach-phong-chong-trong-php-107.html
Leave a Reply