Phát hiện đăng nhập chéo trang dùng thời gian tải, lỗi và redirect để suy ra bạn đăng nhập đâu — cơ chế hoạt động và cách trình duyệt chặn nó.
Điểm chính
- Trạng thái đăng nhập là một kênh phụ (side channel). Same-Origin Policy ngăn một trang web đọc cookie hay dữ liệu phiên của bạn trên origin khác, nhưng nó chưa bao giờ cam kết giấu việc một tài nguyên có hành xử khác đi chỉ vì bạn đã đăng nhập ở nơi khác.
- Dò qua tài nguyên và thời gian tải khai thác cache và độ trễ: một URL chỉ tải nhanh (hoặc chỉ tải được) khi có phiên đăng nhập sẽ để lộ đúng một bit thông tin mỗi lần trang của kẻ tấn công gửi yêu cầu tới nó.
- Phát hiện qua redirect và sự kiện lỗi theo dõi sự kiện
onload/onerror, hoặc báo cáo vi phạm CSP, phát sinh từ thẻ<img>,<script>hay<link>ẩn trỏ tới một endpoint yêu cầu đăng nhập — phiên đã đăng nhập và chưa đăng nhập tạo ra kết quả khác nhau, quan sát được. - Nó tiết lộ điều gì: đối chiếu tín hiệu này trên hàng chục trang web dựng nên một hồ sơ về ngân hàng, cổng y tế, diễn đàn hay ứng dụng hẹn hò bạn đang dùng — mà không cần biết tên bạn, chính điều này khiến nó cực kỳ hữu ích cho lừa đảo (phishing) nhắm mục tiêu.
- Chặn cookie bên thứ ba, phân vùng lưu trữ (storage partitioning) và phân vùng cache đóng phần lớn các lỗ hổng này. Khi trình duyệt không còn gắn cookie phiên của một trang vào các yêu cầu chéo trang, tài nguyên bị dò luôn trông như "đã đăng xuất" bất kể trạng thái thật. Chrome là ngoại lệ một phần: nó phân vùng cache và bộ nhớ lưu trữ theo mặc định, nhưng vẫn gửi cookie bên thứ ba cho tới khi bạn tự bật chế độ chặn.
Phát hiện đăng nhập chéo trang thực chất là gì
Phát hiện đăng nhập chéo trang thuộc nhóm kênh phụ của trình duyệt gọi là XS-Leaks (rò rỉ chéo trang). Same-Origin Policy làm rất tốt một việc cụ thể: ngăn attacker.example đọc nội dung phản hồi từ bank.example. Nhưng nó chưa bao giờ được thiết kế để ngăn attacker.example gửi yêu cầu tới tài nguyên đó và quan sát hành vi của yêu cầu — và chỉ riêng hành vi thôi cũng thường đủ để trả lời một câu hỏi có/không như "người dùng này có đang đăng nhập vào bank.example không".
Phiên bản đơn giản nhất trông như thế này: trang của kẻ tấn công nhúng một thẻ <img> ẩn có src trỏ tới https://bank.example/account/avatar.png. Nếu bạn đã đăng nhập ngân hàng đó, trình duyệt tự động gắn cookie phiên, máy chủ trả về ảnh thật, sự kiện load được kích hoạt. Nếu bạn chưa đăng nhập, cùng yêu cầu đó bị chuyển hướng tới trang đăng nhập hoặc bị từ chối, phản hồi không phải ảnh hợp lệ, và thay vào đó error được kích hoạt. Kẻ tấn công không bao giờ thấy chi tiết tài khoản của bạn — họ chỉ cần biết sự kiện nào đã xảy ra. Trang tổng quan về rò rỉ chéo trang (XS-Leaks) của MDN xếp kỹ thuật này, cùng các kỹ thuật khác dưới đây, vào một nhóm lỗ hổng bảo mật trình duyệt tồn tại liên tục, chứ không phải một lỗi khai thác đơn lẻ.
Dò tài nguyên và thời gian tải nhắm vào các endpoint đã biết
Phiên bản dựa trên sự kiện ở trên chỉ là dạng thô nhất. Một nhóm kỹ thuật tinh vi hơn dựa vào thời gian tải thay vì tín hiệu đạt/không đạt rõ ràng. Trình duyệt cung cấp Resource Timing API (performance.getEntriesByType('resource')), báo cáo một yêu cầu mất bao lâu, và với tài nguyên cùng origin hoặc được cho phép qua Timing-Allow-Origin, còn báo cáo cả số byte đã truyền. Điều này mở ra hai hướng tấn công:
- Dò thời gian qua cache. Nếu một tài nguyên chỉ được yêu cầu — và do đó chỉ được cache — bởi những người dùng đang thực sự sử dụng trang đích (một gói script chỉ tải khi đã đăng nhập, hay một phản hồi API xác thực được nhúng vào trang), thì yêu cầu tiếp theo từ trang kẻ tấn công sẽ gần như tức thời trúng cache đối với những người dùng đó, còn với người khác thì phải đi qua mạng. Chỉ riêng chênh lệch thời gian đã đủ trả lời câu hỏi về trạng thái đăng nhập.
- Đếm frame và số yêu cầu. Một số trang chỉ truy cập được khi đã đăng nhập render nhiều tài nguyên con hơn phiên bản chưa đăng nhập (widget bổ sung, module cá nhân hóa, thêm redirect). Đếm số yêu cầu hoặc số frame mà một lần tải trang kích hoạt là đủ để phân biệt hai trạng thái mà không cần đọc nội dung phản hồi. Thuộc tính
window.length— số frame bên trong một cửa sổ — là một trong số ít thuộc tính mà nền tảng web cố ý cho phép đọc xuyên origin, nên kẻ tấn công chỉ cần mở trang đích trong một cửa sổ pop-up hay iframe là đọc được số frame của nó, dù mọi chi tiết khác của tài liệu đó vẫn nằm ngoài tầm với.
Cả hai cách dò đều không cần quyền truy cập JavaScript vào origin đích: mọi thứ kẻ tấn công đo lường đều diễn ra trong ngữ cảnh thực thi trang của chính họ — đây chính xác là lý do các kỹ thuật này tồn tại lâu như vậy: dưới góc nhìn của trình duyệt, chúng không giống một vi phạm same-origin.
Phát hiện qua redirect và sự kiện lỗi
Biến thể redirect đẩy ý tưởng đó đi xa hơn. Thay vì chỉ dựa vào onerror, kẻ tấn công có thể gắn kèm yêu cầu với một Content-Security-Policy nghiêm ngặt chỉ cho phép kết nối tới origin dự kiến của tài nguyên, rồi lắng nghe sự kiện securitypolicyviolation. Nếu một yêu cầu chưa đăng nhập bị chuyển hướng tới trang đăng nhập lưu trên origin khác, CSP sẽ chặn redirect đó và kích hoạt vi phạm mà kẻ tấn công quan sát được. Một yêu cầu đã đăng nhập trả về tài nguyên trực tiếp, không có redirect nào, sẽ không kích hoạt chính sách đó. Sự có mặt hay vắng mặt của đúng một sự kiện đó trở thành "oracle" — cỗ máy trả lời có/không cho kẻ tấn công. Đây là một trong những mẫu hình XS-Leak dựa trên sự kiện lỗi và CSP mà giới nghiên cứu bảo mật đã ghi nhận trên nhiều trang web suốt nhiều năm qua.
Điều khiến kỹ thuật dò qua redirect bền vững là nó không phụ thuộc vào một lỗi cụ thể nào trong mã nguồn của trang đích — nó chỉ phụ thuộc vào việc trang đích hành xử khác nhau ở đâu đó trong chuỗi phản hồi giữa khách đã đăng nhập và chưa đăng nhập, điều gần như đúng với bất kỳ dịch vụ nào có rào cản xác thực.
Điều này tiết lộ gì về bạn
Một câu trả lời có/không đơn lẻ — "đăng nhập bank.example: có" — tự nó không quá nhạy cảm. Rủi ro chồng chất khi kẻ tấn công chạy cùng phép dò đó trên danh sách hàng chục hoặc hàng trăm trang web đã biết: ngân hàng, cổng thông tin y tế, ứng dụng hẹn hò, diễn đàn gắn với cộng đồng chính trị hoặc tôn giáo cụ thể, trang web người lớn, mạng nội bộ công ty. Bản đồ bit "đã đăng nhập" kết quả là một dấu vân tay hành vi khác — và thường nhạy cảm hơn — so với dấu vân tay thiết bị được nói tới trong hướng dẫn về dấu vân tay trình duyệt của chúng tôi, vì nó chỉ thẳng ra bạn dùng dịch vụ nào, chứ không chỉ thu hẹp phạm vi thiết bị bạn đang dùng.
Hồ sơ đó ngay lập tức hữu ích cho lừa đảo nhắm mục tiêu: một email nêu đúng tên ngân hàng thật của bạn, thay vì đoán chung chung "Vietcombank hay Techcombank, chọn đại một cái", sẽ thuyết phục hơn rất nhiều. Nó cũng là một vector bóc trần danh tính (deanonymization) độc lập — tổ hợp cụ thể các dịch vụ mà một người đã đăng nhập có thể nhận diện gần chính xác như dấu vân tay thiết bị, mà không mang theo nhiễu kỹ thuật vốn có trong các chỉ số canvas hay WebGL.
Cơ chế phòng thủ của trình duyệt: phân vùng, chặn cookie và Fetch Metadata
Giải pháp mang tính cấu trúc không phải là vá từng endpoint bị rò — một trang web có thể có hàng nghìn endpoint như vậy — mà là loại bỏ hành vi trình duyệt mà phần lớn các kỹ thuật này phụ thuộc vào: một yêu cầu chéo trang âm thầm mang theo cookie phiên của trang đích.
Chặn cookie bên thứ ba và phân vùng lưu trữ chính là làm việc đó. Total Cookie Protection của Firefox cấp cho mỗi tài nguyên bên thứ ba một "hũ cookie" riêng, khóa theo trang cấp cao nhất bạn đang truy cập, nên cookie phiên của bank.example đơn giản là không được gắn vào khi attacker.example gửi yêu cầu — tài nguyên bị dò luôn trông như đã đăng xuất, vô điều kiện, bất kể trạng thái phiên thật của bạn. Chặn toàn diện cookie bên thứ ba của Safari đạt cùng kết quả cuối bằng cách chặn mặc định thay vì dùng khóa phân vùng. Chrome là ngoại lệ một phần đáng lưu ý: nó cũng có cơ chế phân vùng lưu trữ riêng, cộng thêm cơ chế tùy chọn CHIPS cho những trường hợp hợp lệ (widget nhúng, cân bằng tải CDN) vẫn cần một chút trạng thái xuyên trang nhưng không phải theo dõi xuyên trang — nhưng sau vài lần hoãn, Google đã từ bỏ kế hoạch tắt cookie bên thứ ba cho tất cả mọi người. Một cửa sổ Chrome mặc định vẫn gắn chúng; cửa sổ ẩn danh thì chặn.
Tuy vậy, cookie không phải toàn bộ câu chuyện. Phép dò thời gian qua cache hoàn toàn không cần cookie trên chính yêu cầu dò — nó đọc một mục cache mà lần truy cập đã đăng nhập trước đó của bạn để lại. Ở đây là một cơ chế khác: các trình duyệt nay phân vùng HTTP cache theo trang cấp cao nhất, nên tài nguyên được cache khi bạn đang ở bank.example được lưu dưới một khóa khác với cùng URL đó khi được yêu cầu từ một trang trên attacker.example, và yêu cầu của kẻ tấn công luôn trượt cache. Chrome và Firefox đều triển khai điều này trong giai đoạn 2020–2021, còn WebKit đã phân vùng trạng thái mạng từ sớm hơn nữa — đó là lý do các phép dò qua cache lụi tàn ngay cả trên những trình duyệt vẫn gửi cookie bên thứ ba theo mặc định.
Một cơ chế phòng thủ phía máy chủ bổ trợ là các tiêu đề Fetch Metadata, đặc biệt là Sec-Fetch-Site. Vì các tiêu đề này do trình duyệt sinh ra và không thể giả mạo từ JavaScript, máy chủ có thể kiểm tra Sec-Fetch-Site: cross-site trên một yêu cầu tới endpoint nhạy cảm, yêu cầu đăng nhập, và đơn giản là từ chối phục vụ — chặn đứng lỗ rò ngay tại nơi sở hữu dữ liệu, bất kể khách truy cập dùng trình duyệt nào. Hai lớp phòng thủ này bổ trợ lẫn nhau: cơ chế phân vùng phía trình duyệt bảo vệ bạn ngay cả trên các trang chưa áp dụng Fetch Metadata, còn Fetch Metadata bảo vệ người dùng trên các trình duyệt vẫn mặc định gửi cookie bên thứ ba.
Tổng hợp lại
Phát hiện đăng nhập chéo trang là "họ hàng" của các kỹ thuật quan sát thụ động, dựa trên sự kiện được nói tới trong hướng dẫn phát hiện bot của chúng tôi — cả hai đều dựa vào việc quan sát thời gian tải, sự kiện lỗi và hành vi phản hồi, thay vì đọc trực tiếp thứ mà kẻ tấn công không được phép thấy. Và nó không thay thế dấu vân tay thiết bị mà cộng hưởng với nó: biết thiết bị nào và tài khoản nào cùng chỉ về một người dùng là tín hiệu mạnh hơn nhiều so với từng thứ riêng lẻ, đó là lý do vì sao hiểu các tín hiệu vân tay cộng dồn ra sao vẫn quan trọng, dù lỗ rò cụ thể ở đây nói về trạng thái đăng nhập chứ không phải phần cứng.
Tin tốt là đây là một trong số ít kỹ thuật theo dõi mà cách khắc phục thực sự nằm ở trình duyệt, chứ không phải ở thói quen của bạn. Trên Firefox hay Safari phiên bản hiện hành với các biện pháp bảo vệ mặc định được bật, những phép dò phụ thuộc cookie nói trên đã chết — cookie phiên mà chúng dựa vào không bao giờ rời khỏi trang đã thiết lập nó. Trên Chrome, các phép dò thời gian qua cache cũng đã bị chặn theo mặc định, nhưng nhóm dựa trên cookie thì vẫn còn nguyên cho tới khi bạn tự bật chặn cookie bên thứ ba — điều đó khiến đây là thay đổi đáng giá nhất bạn có thể thực hiện trước cả lớp lỗ rò này.
Bản thân trạng thái đăng nhập là thứ một trang web không thể cho bạn xem — phép dò chạy trên trang của người khác, và theo đúng thiết kế, bạn không bao giờ thấy câu trả lời. Thứ bạn có thể kiểm tra là phần bề mặt còn lại mà kẻ tấn công sẽ ghép chung với nó: kiểm tra dấu vân tay của BrowserInsight liệt kê các tín hiệu canvas, WebGL, phông chữ và lưu trữ mà trình duyệt bạn đang phơi ra, tất cả được đo ngay trong trình duyệt của bạn và không bao giờ được gửi đi đâu để phân tích.
Câu hỏi thường gặp
Một trang web có thực sự biết tôi đã đăng nhập ngân hàng chỉ bằng cách tôi ghé một trang khác không?
Với các kỹ thuật nói trên, trước đây điều này hoàn toàn có thể làm được một cách ổn định. Trong một trình duyệt chặn cookie bên thứ ba theo mặc định — Firefox và Safari phiên bản hiện hành đều như vậy — cookie phiên ngân hàng của bạn không còn được gắn vào yêu cầu chéo trang, nên tài nguyên bị dò luôn trông như đã đăng xuất bất kể phiên thật của bạn, và ngân hàng không cần thay đổi gì cả. Khoảng trống còn lại là Chrome: phân vùng cache và bộ nhớ lưu trữ đã bật mặc định và triệt tiêu các phép dò thời gian, nhưng cookie bên thứ ba vẫn được gửi trừ khi bạn bật chặn trong phần cài đặt quyền riêng tư hoặc duyệt ở chế độ ẩn danh.
Chế độ duyệt web riêng tư/ẩn danh có ngăn được phát hiện đăng nhập không?
Phần lớn là có, nhưng vì một lý do gián tiếp: trong cửa sổ riêng tư bạn thường chẳng đăng nhập vào đâu cả, nên mọi phép dò đều thành thật trả lời "chưa đăng nhập". Ngoài điều đó ra, chế độ riêng tư không thay đổi luật chơi — bên trong một phiên riêng tư đang hoạt động, hành vi cookie chéo trang vẫn phụ thuộc vào cùng các cài đặt chặn cookie bên thứ ba và phân vùng như khi duyệt web bình thường. Ngoại lệ đáng lưu ý là Chrome: nó chặn cookie bên thứ ba theo mặc định ở chế độ ẩn danh nhưng không chặn ở cửa sổ thường, nên trên Chrome, cửa sổ riêng tư thực sự đóng được những phép dò mà cửa sổ thường để ngỏ.
Điều này có giống với lấy dấu vân tay trình duyệt không?
Không, và sự khác biệt quan trọng. Lấy dấu vân tay nhận diện thiết bị của bạn qua các thuộc tính kỹ thuật như font chữ, kết xuất GPU, kích thước màn hình. Phát hiện đăng nhập nhận diện bạn đang giữ tài khoản nào, dựa vào cách trình duyệt xử lý cookie chứ không phải bất kỳ thuộc tính thiết bị nào. Một kẻ tấn công nắm cả hai tín hiệu có thể gắn một thiết bị cụ thể với một tập dịch vụ cụ thể ngoài đời — kết hợp cả hai mạnh hơn nhiều so với dùng riêng từng cái.
Trang web có thể tự khắc phục việc này mà không cần chờ trình duyệt không?
Có thể khắc phục một phần. Áp dụng tiêu đề Fetch Metadata cho phép trang web từ chối thẳng các yêu cầu chéo trang tới endpoint yêu cầu đăng nhập, đóng lỗ rò cho mọi khách truy cập bất kể trình duyệt nào. Nhưng điều này đòi hỏi chính trang web đó phải triển khai đúng trên từng endpoint nhạy cảm, đó là lý do vì sao cơ chế phân vùng phía trình duyệt — bảo vệ khách truy cập ngay cả khi trang web chưa làm việc đó — đã trở thành tuyến phòng thủ chính.


