V. Phân tích, khai thác và ngăn chặn lỗ hổng CSRF với header Referer
1. Header Referer - ưu, nhược điểm
Trong các HTTP header có một header Referer ghi lại địa chỉ (địa chỉ nguồn) ngay trước khi browser truy cập tới địa chỉ hiện tại (địa chỉ đích). Thông thường, địa chỉ trước khi truy cập tới một chức năng nằm trong miền domain con của ứng dụng.
Ví dụ browser truy cập tới http://bank.example/withdraw?account=Viblo&amount=1000000&for=Sun
thì trước đó cần đăng nhập vào bank.example
và click vào một tùy chọn nào đó trong giao diện web để kích hoạt sự kiện chuyển khoản. Khi đó header Referer sẽ hiển thị trang web chứa tùy chọn kích hoạt sự kiện đó. Khi kẻ tấn công tạo payload đánh lừa nạn nhân chuyển hướng từ một website khác thì header Referer sẽ nhận giá trị là địa chỉ website của kẻ tấn công. Bởi vậy chúng ta có thể sử dụng header Referer*thực hiện kiểm tra trang web nguồn chuyển hướng tới chức năng cần bảo vệ có hợp lệ hay không. Ví dụ trang web kiểm tra request có tới từ các trang cùng domain www.bank-website.com
<?php
$referer = $_SERVER['HTTP_REFERER'];
$expected_referer = "https://www.bank-website.com"; $referer_host = parse_url($referer, PHP_URL_HOST);
$expected_referer_host = parse_url($expected_referer, PHP_URL_HOST); if ($referer_host === $expected_referer_host) { // process the transfer money form // ...
} else { // the request is not from the expected origin, block the request // ...
}
?>
Biện pháp này có ưu điểm là đơn giản, dễ dàng cài đặt, không cần thay đổi quá nhiều vào chương trình cũ và luồng hoạt động với các ứng dụng đã đi vào vận hành.
Tuy nhiên, do giá trị Referer được cung cấp từ browser, nên không thể tránh khỏi việc kẻ tấn công lợi dụng các lỗ hổng bảo mật tới từ chính bản thân các browser. Hay nói cách khác, việc sử dụng header Referer bảo vệ tấn công CSRF đang phó thác kiểm tra an toàn vào bên thứ ba (các browser), trên lý thuyết thì cách làm này không thực sự an toàn, do không thể đảm bảo bản thân các browser không chứa lỗ hổng. (Thực tế đã có phương pháp thay đổi giá trị Referer trên các browser như IE6 hoặc FF2)
Sử dụng header Referer cũng đồng nghĩa với việc luôn ghi lại nguồn truy cập của người dùng. Một số người dùng lo sợ một số thông tin cá nhân bị xâm phạm, hoặc vô tình bị lộ các thông tin từ mạng nội bộ ra mạng chung, nên họ có thể cài đặt trong browser của họ nhằm tắt tính năng cung cấp header Referer. Như vậy khi truy cập các chức năng được bảo vệ tấn công, có thể xuất hiện false positive (cảnh báo giả) lầm tưởng là các cuộc tấn công CSRF. Trong các mục tiếp theo chúng ta sẽ cùng phân tích một số dạng tấn công CSRF dựa vào header Referer.
2. Tấn công CSRF bỏ qua header Referer
Xem xét đoạn code bằng PHP xử lý kiểm tra tấn công CSRF qua header Referer như sau:
<?php
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$expected_referer = "https://www.bank-website.com"; if ($referer) { $referer_host = parse_url($referer, PHP_URL_HOST); $expected_referer_host = parse_url($expected_referer, PHP_URL_HOST); if ($referer_host !== $expected_referer_host) { // the request is not from the expected origin, block the request // ... exit; }
} // process the transfer money form
// ...
?>
Không khó khăn để nhận ra cơ chế ngăn chặn tấn công CSRF qua header Referer trong chương trình trên chỉ hoạt động khi giá trị $referer
tồn tại. Sự bất cẩn từ phía lập trình viên đã khiến kẻ tấn công có thể vượt qua cơ chế kiểm tra bằng việc loại bỏ hoặc vô hiệu hóa header Referer trong browser nạn nhân (Thậm chí nạn nhân tự cài đặt không sử dụng header Referer trong trình duyệt cá nhân cũng có thể dẫn tới lỗ hổng). Một cách đơn giản để thực hiện mục đích là sử dụng thẻ <meta>
:
<meta name="referrer" content="never">
Bạn đọc có thể luyện tập phương thức tấn công này trong bài lab CSRF where Referer validation depends on header being present
3. Tấn công CSRF khi quy trình kiểm tra header Referer không chặt chẽ
Trong quá trình xây dựng quy trình kiểm tra header Referer, có thể lập trình viên mắc các lỗi logic (điều này khó tránh khỏi). Khi kẻ tấn công thông qua thử nghiệm nắm được cách hoạt động của quy trình kiểm tra sẽ cố gắng tìm cách vượt qua cơ chế này.
Ví dụ trong đoạn code sau:
<?php
$referer = $_SERVER['HTTP_REFERER'];
$expected_referer_prefix = "https://www.bank-website.com"; $referer_host = parse_url($referer, PHP_URL_HOST); if (strpos($referer_host, $expected_referer_prefix) !== 0) { // the request is not from the expected origin, block the request // ... exit;
} // process the transfer money form
// ...
?>
Chương trình trên chỉ kiểm tra domain địa chỉ nguồn của người dùng bắt đầu bằng domain đặc biệt hay không. Hình thức kiểm tra này có thể bị kẻ tấn công bypass khi họ đăng ký và sử dụng domain theo đúng yêu cầu kiểm tra, hoặc bypass với cơ chế làm việc của URL:
http://bank-website.com.attacker-website.com/csrf-attack
Một ví dụ khác:
<?php
$referer = $_SERVER['HTTP_REFERER'];
$expected_referer_domain = "bank-website.com"; $referer_host = parse_url($referer, PHP_URL_HOST); if (strpos($referer_host, $expected_referer_domain) === false) { // the request is not from the expected origin, block the request // ... exit;
} // process the transfer money form
// ...
?>
Chương trình trên kiểm tra sự tồn tại của chuỗi bank-website.com trong giá trị header Referer. Kẻ tấn công dễ dàng bypass như sau:
http://attacker-website.com/csrf-attack?vulnerable-website.com
Bạn đọc có thể tìm hiểu phương thức hoạt động của cơ chế bảo vệ tân công trong bài lab CSRF with broken Referer validation và tìm cách bypass nó.
VI. Phân tích, khai thác và ngăn chặn lỗ hổng CSRF với SameSite Cookie
1. Giới thiệu về SameSite Cookie
Ngoài các phương pháp đã xét, SameSite Cookie cũng được sử dụng ngăn chặn tấn công CSRF. Biện pháp này tập trung vào các giá trị Cookie trong request, đưa ra các quy định khác nhau cho cookies.
Trước hết, chúng ta cần hiểu về khái niệm site trong tình huống này. site được cấu tạo từ phần: top-level domain (TLD - các tên miền cao nhất như .com
, .net
, .xyz
, ...), phần TLD+1 đứng ngay phía trước TLD, cùng với scheme (http
, https
, ...).
Khác với site, origin bao gồm toàn bộ URL:
Như vậy, SameSite tức là hai URL có cùng scheme, TLD, TLD+1. SameOrigin là toàn bộ URL cần hoàn toàn giống nhau. Các bạn có thể theo dõi bảng sau để hiểu rõ hơn thuật ngữ SameSite:
Request from | Request to | SameSite | SameOrigin |
---|---|---|---|
https://viblo.asia | https://viblo.asia | Yes | Yes |
https://ctf.viblo.asia | https://code.viblo.asia | Yes | No: mismatched domain name |
https://viblo.asia | https://viblo.asia:8080 | Yes | No: mismatched port |
https://viblo.asia | https://viblo.co.uk | No: mismatched eTLD | No: mismatched domain name |
https://viblo.asia | http://viblo.asia | No: mismatched scheme | No: mismatched scheme |
Các tài liệu tham khảo
- https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CSRF%20Injection
- https://book.hacktricks.xyz/pentesting-web/csrf-cross-site-request-forgery
- https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions