kỹ thuật tấn công SQL Injection và cách phòng chống trong php

Ơ 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ậpmật khẩu.

Đăng nhập tấn công sql injection

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'";
Trường hợp 1: Bây giờ tôi nhập username = thehalfheartpassword = 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 = somenamepassword = 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;
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);
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);
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"));
Kết quả là: SELECT * FROM member WHERE username = 'thehalfheart' AND password = 'matkhau'.

 

Đang Cập Nhật Thêm ...

 

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.

Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website lấy nội dung mà không để nguồn hoặc copy bài với số lượng lớn.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Group Facebook để được hỗ trợ nhanh nhất.