Điều gì tạo nên trải nghiệm đăng xuất tốt?

Kenji Baheux
Kenji Baheux

Khi đăng xuất khỏi một trang web, người dùng đang cho biết họ cần thoát hoàn toàn khỏi trải nghiệm người dùng được cá nhân hoá. Do đó, điều quan trọng là bạn phải tuân thủ mô hình tinh thần của người dùng càng sát càng tốt. Ví dụ: trải nghiệm đăng xuất phù hợp cũng phải tính đến mọi thẻ mà người dùng có thể đã mở trước khi quyết định đăng xuất.

Để mang lại trải nghiệm đăng xuất tuyệt vời, bạn cần đảm bảo tính nhất quán về mặt hình ảnh và trạng thái trong trải nghiệm người dùng. Hướng dẫn này đưa ra lời khuyên cụ thể về những điều cần chú ý và cách đạt được trải nghiệm đăng xuất tốt.

Một số điểm chính cần cân nhắc

Khi triển khai chức năng đăng xuất trên trang web của bạn, hãy chú ý đến những khía cạnh sau để đảm bảo quy trình đăng xuất diễn ra suôn sẻ, an toàn và trực quan:

  • Trải nghiệm người dùng rõ ràng và nhất quán khi đăng xuất: Cung cấp một nút hoặc đường liên kết đăng xuất rõ ràng và luôn hiển thị, dễ nhận biết và truy cập trên toàn bộ trang web. Tránh sử dụng nhãn mơ hồ hoặc ẩn chức năng đăng xuất trong các trình đơn, trang con hoặc vị trí không trực quan khác.
  • Lời nhắc xác nhận: Triển khai lời nhắc xác nhận trước khi hoàn tất quy trình đăng xuất. Điều này có thể giúp ngăn người dùng vô tình đăng xuất và cho phép người dùng cân nhắc lại xem họ có thực sự cần đăng xuất hay không (ví dụ: nếu họ siêng năng khoá thiết bị bằng mật khẩu mạnh hoặc cơ chế xác thực khác).
  • Xử lý nhiều thẻ: Nếu người dùng đã mở một số trang từ cùng một trang web trong các thẻ khác nhau, hãy đảm bảo rằng việc đăng xuất khỏi một thẻ cũng sẽ cập nhật tất cả các thẻ đang mở khác của trang web đó.
  • Chuyển hướng đến một trang đích an toàn: Sau khi đăng xuất thành công, hãy chuyển hướng người dùng đến một trang đích an toàn cho biết rõ rằng họ không còn đăng nhập nữa. Tránh chuyển hướng người dùng đến những trang có thông tin được cá nhân hoá. Tương tự, hãy đảm bảo rằng các thẻ khác cũng không còn phản ánh trạng thái đã đăng nhập. Ngoài ra, hãy đảm bảo rằng bạn không tạo ra một lệnh chuyển hướng mở mà kẻ tấn công có thể lợi dụng.
  • Dọn dẹp phiên: Sau khi người dùng đăng xuất, hãy xoá hoàn toàn mọi dữ liệu phiên người dùng nhạy cảm, cookie hoặc tệp tạm thời được liên kết với phiên của người dùng. Điều này ngăn chặn hành vi truy cập trái phép vào thông tin người dùng hoặc hoạt động trong tài khoản, đồng thời ngăn trình duyệt khôi phục các trang có thông tin nhạy cảm từ nhiều bộ nhớ đệm, đặc biệt là bộ nhớ đệm cho thao tác tiến/lùi.
  • Xử lý lỗi và phản hồi: Cung cấp thông báo lỗi hoặc phản hồi rõ ràng cho người dùng nếu có vấn đề khi họ đăng xuất. Thông báo cho họ về mọi rủi ro bảo mật hoặc rò rỉ dữ liệu tiềm ẩn nếu quy trình đăng xuất không thành công.
  • Những điểm cần lưu ý về khả năng hỗ trợ tiếp cận: Đảm bảo rằng người dùng khuyết tật có thể sử dụng cơ chế đăng xuất, kể cả những người dùng công nghệ hỗ trợ như trình đọc màn hình hoặc thao tác bằng bàn phím.
  • Khả năng tương thích trên nhiều trình duyệt: Kiểm thử chức năng đăng xuất trên nhiều trình duyệt và thiết bị để đảm bảo chức năng này hoạt động nhất quán và đáng tin cậy.
  • Liên tục giám sát và cập nhật: Thường xuyên giám sát quy trình đăng xuất để phát hiện mọi lỗ hổng bảo mật hoặc điểm yếu bảo mật tiềm ẩn. Triển khai các bản cập nhật và bản vá kịp thời để giải quyết mọi vấn đề đã xác định.
  • Liên kết danh tính: Nếu người dùng đăng nhập bằng danh tính được liên kết, hãy xem liệu việc đăng xuất khỏi nhà cung cấp danh tính cũng được hỗ trợ và cần thiết hay không. Ngoài ra, nếu nhà cung cấp danh tính hỗ trợ tính năng tự động đăng nhập, đừng quên ngăn chặn tính năng này.

DO

  • Nếu bạn vô hiệu hoá một cookie trên máy chủ trong quy trình đăng xuất (hoặc các quy trình thu hồi quyền truy cập khác), hãy nhớ xoá cookie đó trên thiết bị của người dùng.
  • Dọn dẹp mọi dữ liệu nhạy cảm mà bạn có thể đã lưu trữ trên thiết bị của người dùng: cookie, localStorage, sessionStorage, indexedDB, CacheStorage và mọi kho lưu trữ dữ liệu cục bộ khác.
  • Đảm bảo rằng mọi tài nguyên chứa dữ liệu nhạy cảm (đặc biệt là tài liệu HTML) đều được trả về bằng tiêu đề HTTP Cache-control: no-store để trình duyệt không lưu trữ những tài nguyên này trong bộ nhớ vĩnh viễn (ví dụ: trên đĩa). Tương tự, các lệnh gọi XHR/fetch trả về dữ liệu nhạy cảm cũng phải đặt tiêu đề HTTP Cache-Control: no-store để ngăn mọi hoạt động lưu vào bộ nhớ đệm.
  • Đảm bảo rằng mọi thẻ đang mở trên thiết bị của người dùng đều được cập nhật theo các lệnh thu hồi quyền truy cập phía máy chủ.

Dọn dẹp dữ liệu nhạy cảm khi đăng xuất

Sau khi đăng xuất, hãy cân nhắc việc xoá dữ liệu nhạy cảm tạm thời và dữ liệu nhạy cảm được lưu trữ cục bộ. Việc tập trung vào dữ liệu nhạy cảm là do nếu xoá mọi thứ, trải nghiệm người dùng sẽ trở nên tệ hơn đáng kể vì người dùng này có thể sẽ quay lại. Ví dụ: nếu bạn xoá tất cả dữ liệu được lưu trữ cục bộ, thì người dùng sẽ phải xác nhận lại lời nhắc đồng ý sử dụng cookie và thực hiện các quy trình khác như thể họ chưa từng truy cập vào trang web của bạn.

Cách dọn dẹp cookie

Trong phản hồi cho trang xác nhận trạng thái đã đăng xuất, hãy đính kèm tiêu đề HTTP Set-Cookie để xoá mọi cookie liên quan đến hoặc chứa dữ liệu nhạy cảm. Đặt giá trị expires thành một ngày trong quá khứ xa xôi và đặt giá trị của cookie thành một chuỗi trống để đảm bảo.

Set-Cookie: sensitivecookie1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure
Set-Cookie: sensitivecookie2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure
...

Trường hợp không có mạng

Mặc dù phương pháp được mô tả ở trên là đủ cho các trường hợp sử dụng chung, nhưng phương pháp này sẽ không hoạt động nếu người dùng đang làm việc khi không có mạng. Bạn nên cân nhắc việc yêu cầu 2 cookie để theo dõi trạng thái đã đăng nhập: một cookie chỉ HTTPS bảo mật và một cookie thông thường có thể truy cập qua JavaScript. Nếu người dùng đang tìm cách đăng xuất khi không có mạng, bạn có thể xoá cookie JavaScript và tiếp tục các thao tác dọn dẹp khác nếu có thể. Nếu có một worker dịch vụ, bạn cũng có thể tận dụng Background Fetch API để thử lại yêu cầu xoá trạng thái trên máy chủ khi người dùng kết nối mạng sau này.

Cách dọn dẹp bộ nhớ

Trên phản hồi cho trang xác nhận trạng thái đã đăng xuất, hãy nhớ dọn dẹp dữ liệu nhạy cảm khỏi nhiều kho dữ liệu:

  • sessionStorage: Mặc dù dữ liệu này sẽ bị xoá khi người dùng kết thúc phiên hoạt động với trang web của bạn, nhưng hãy cân nhắc việc chủ động dọn dẹp dữ liệu nhạy cảm khi người dùng đăng xuất, phòng trường hợp họ quên đóng tất cả các thẻ đã mở trên trang web của bạn.

    // Remove sensitive data from sessionStorage
    sessionStorage.removeItem('sensitiveSessionData1');
    // ...
    
    // Or if everything in sessionStorage is sensitive, clear it all
    sessionStorage.clear();
    
  • localStorage, indexedDB, Cache/Service Worker API: Khi người dùng đăng xuất, hãy dọn dẹp mọi dữ liệu nhạy cảm mà bạn có thể đã lưu trữ bằng các API này, vì dữ liệu đó sẽ duy trì trong các phiên.

    // Remove sensitive data from localStorage:
    localStorage.removeItem('sensitiveData1');
    // ...
    
    // Or if everything in localStorage is sensitive, clear it all:
    localStorage.clear();
    
    // Delete sensitive object stores in indexedDB:
    const name = 'exampleDB';
    const version = 1;
    const request = indexedDB.open(name, version);
    
    request.onsuccess = (event) => {
      const db = request.result;
      db.deleteObjectStore('sensitiveStore1');
      db.deleteObjectStore('sensitiveStore2');
    
      // ...
    
      db.close();
    }
    
    // Delete sensitive resources stored with the Cache API:
    caches.open('cacheV1').then((cache) => {
      await cache.delete("/personal/profile.png");
    
      // ...
    }
    
    // Or better yet, clear a cache bucket that contains sensitive resources:
    caches.delete('personalizedV1');
    

Cách dọn dẹp bộ nhớ đệm

  • Bộ nhớ đệm HTTP: Miễn là bạn đặt Cache-control: no-store trên các tài nguyên có dữ liệu nhạy cảm, bộ nhớ đệm HTTP sẽ không giữ lại bất kỳ dữ liệu nhạy cảm nào.
  • Bộ nhớ đệm tiến/lùi: Tương tự, nếu bạn làm theo các đề xuất về Cache-control: no-store và về việc xoá cookie nhạy cảm (ví dụ: cookie chỉ HTTPS bảo mật liên quan đến hoạt động xác thực) khi người dùng đăng xuất, thì bạn không cần lo lắng về việc dữ liệu nhạy cảm được giữ lại trong bộ nhớ đệm tiến/lùi. Thật vậy, tính năng bộ nhớ đệm cho thao tác tiến/lùi sẽ loại bỏ các trang cùng nguồn gốc được phân phát bằng tiêu đề HTTP Cache-control: no-store nếu nhận thấy một hoặc nhiều tín hiệu sau:
    • Một hoặc nhiều cookie chỉ HTTPS bảo mật đã bị sửa đổi hoặc xoá.
    • Một hoặc nhiều phản hồi cho các lệnh gọi XHR/fetch (do trang phát hành) có chứa tiêu đề HTTP Cache-control: no-store.

Trải nghiệm nhất quán cho người dùng trên các thẻ

Người dùng có thể đã mở nhiều thẻ cho trang web của bạn trước khi quyết định đăng xuất. Đến lúc đó, họ có thể đã quên các thẻ khác, hoặc thậm chí là các cửa sổ trình duyệt khác. Bạn nên tránh việc dựa vào người dùng để đóng tất cả các thẻ và cửa sổ có liên quan. Thay vào đó, hãy chủ động đảm bảo trạng thái đăng nhập của người dùng nhất quán trên các thẻ.

Cách thực hiện

Để đạt được trạng thái đăng nhập nhất quán trên các thẻ, hãy cân nhắc sử dụng kết hợp các sự kiện pageshow/pagehide và Broadcast Channel API.

  • Sự kiện pageshow: Khi có một pageshow được duy trì, hãy kiểm tra trạng thái đăng nhập của người dùng và xoá dữ liệu nhạy cảm (hoặc thậm chí là toàn bộ trang) nếu người dùng không còn đăng nhập nữa. Sự kiện pageshow sẽ kích hoạt trước khi trang được kết xuất lần đầu tiên sau khi được khôi phục từ thao tác tiến/lùi, để quy trình kiểm tra trạng thái đăng nhập cho phép bạn đặt lại trang về trạng thái không nhạy cảm.

    window.addEventListener('pageshow', (event) => {
      if (event.persisted && !document.cookie.match(/my-cookie)) {
        // The user has logged out.
        // Force a reload, or otherwise clear sensitive information right away.
        body.innerHTML = '';
        location.reload();
      }
    });
    
  • Broadcast Channel API: Sử dụng API này để truyền đạt các thay đổi về trạng thái đăng nhập trên các thẻ và cửa sổ. Nếu người dùng đã đăng xuất, hãy xoá tất cả dữ liệu nhạy cảm hoặc chuyển hướng đến trang đăng xuất trên tất cả các thẻ và cửa sổ có dữ liệu nhạy cảm.

    // Upon logout, broadcast new login state so that other tabs can clean up too:
    const bc = new BroadcastChannel('login-state');
    bc.postMessage('logged out');
    
    // [...]
    const bc = new BroadcastChannel('login-state');
    bc.onMessage = (msgevt) => {
      if (msgevt.data === 'logged out') {
        // Clean up, reload or navigate to the sign-out page.
        // ...
      }
    }
    

Kết luận

Bằng cách làm theo hướng dẫn trong tài liệu này, bạn sẽ có thể thiết kế trải nghiệm đăng xuất tuyệt vời cho người dùng, ngăn chặn trường hợp đăng xuất ngoài ý muốn và bảo vệ thông tin cá nhân của người dùng.