sessionStorage不能跨標簽頁解決方案 未驗證


sessionStorage不能跨標簽頁解決方案


現有的瀏覽器存儲機制

localStorage :~5MB,數據永久保存直到用戶手動刪除
sessionStorage :~5MB,數據只在當前標簽頁有效
cookie :~4KB,可以設置成永久有效
session cookie :~4KB,當用戶關閉瀏覽器時刪除(並非總能立即刪除)
安全的認證token保存

一些重要的系統會要求當用戶關閉標簽頁時會話立刻到期。

為了達到這個目的,不僅絕對不應該使用cookies來保存任何敏感信息(例如認證token)。甚至session-cookies也無法滿足要求,它在標簽頁關閉(甚至瀏覽器完全關閉)后還會持續存活一定時間。

(任何時刻我們都不應該只使用cookies,它還有其他很多問題需要討論,例如CSRF)

這些問題就使得我們在保存認證token時應使用內存或sessionStorage。sessionStorage的好處是它允許跨多個頁面保存數據,並且也支持瀏覽器刷新操作。這樣用戶就可以在多個頁面之間跳轉或刷新頁面而保持登錄狀態。

Good。我們將token保存在sessionStorage,並在每次請求服務器時將token放在請求頭中來完成用戶的身份認證。當用戶關閉標簽頁,token會立即過期。

但多標簽頁怎么辦?

即便是在單頁面應用中也有一個很常見的情況,用戶經常希望打開多個標簽頁。而此場景下將token保存在sessionStorage中將會帶來很差的用戶體驗,每次開啟一個標簽頁都會要求用戶重新登錄。沒錯,sessionStorage不支持跨標簽頁共享數據。

利用localStorage事件來跨標簽頁共享sessionStorage

我利用localStorage事件提出了一種解決方案。

當用戶新開一個標簽頁時,我們先來詢問其它已經打開的標簽頁是不是有需要給我們共享的sessionStorage數據。如果有,現有的標簽頁會通過localStorage事件來傳遞數據到新打開的標簽頁中,我們只需要復制一份到本地sessionStorage即可。

傳遞過來的sessionStorage絕對不會保存在localStorage,從localStorage事件將數據中復制並保存到sessionStorage,這個流程是在同一個調用中完成,沒有中間狀態。而且數據是對應事件攜帶的,並不在localStorage中。(譯者注:作者意圖解釋這個方案的安全性)

在線例子

點擊“Set the sessionStorage”,然后打開多個標簽頁,你會發現sessionStorage共享了。

  1. // 為了簡單明了刪除了對IE的支持
  2. (function(){
  3. if(!sessionStorage.length) {
  4. // 這個調用能觸發目標事件,從而達到共享數據的目的
  5. localStorage.setItem('getSessionStorage',Date.now());
  6. };
  7. // 該事件是核心
  8. window.addEventListener('storage',function(event){
  9. if(event.key =='getSessionStorage') {
  10. // 已存在的標簽頁會收到這個事件
  11. localStorage.setItem('sessionStorage',JSON.stringify(sessionStorage));
  12. localStorage.removeItem('sessionStorage');
  13. } elseif(event.key =='sessionStorage'&& !sessionStorage.length) {
  14. // 新開啟的標簽頁會收到這個事件
  15. vardata =JSON.parse(event.newValue),
  16. value;
  17. for(keyindata) {
  18. sessionStorage.setItem(key, data[key]);
  19. }
  20. }
  21. });
  22. })();

(譯者注:上面的代碼是我從在線demo中截取的,原文中並無提到)

接近完美

我們現在擁有了一個幾乎非常安全的方案來保存會話token在瀏覽器里,並支持良好的多標簽頁用戶體驗。現在當用戶關閉標簽頁后能確保會話立即過期。難道不是么?

chrome和firefox都支持當用戶進行“重新打開關閉的標簽頁”或“撤銷關閉標簽頁”時恢復sessionStorage。F**k!(譯者注:作者原文用的是“Damn it!”,注意到那個嘆號了嗎?)

safari在這個問題上處理是正確的,它並不會恢復sessionStorag(只測試了上述這三個瀏覽器)。

對用戶而言,能夠確定sessionStorag已經過期的方法是直接重新打開網站,而不是選擇“重新打開關閉的標簽頁”。

除非chrome和firefox能夠解決這個bug。(但我預感開發組會稱其為“特性”)

即便存在這樣的bug,使用sessionStorag依然要比session-cookies方案或其他方案要安全。如果我們希望得到一個更加完美的方案,我們就需要自己來實現一個內存的方案來代替sessionStorag。(onbeforeunload也能做到,但不是太可靠且每次刷新頁面也會被清空。window.name也不錯,但它太老了且也不支持跨域保護)

跨標簽頁共享memoryStorage

這應該是唯一一個真正安全的實現瀏覽器端保存認證token的方法了,並且要保證用戶打開多個標簽頁不需要重新登錄。

關閉標簽頁,會話立即過期–這次是真真兒的。

這個方案的缺點是, 當只有一個標簽頁時 ,瀏覽器刷新會導致用戶重新登錄。安全總是要付出點代價的,很明顯這個缺點可能是致命的。

在線例子

設置一個memoryStorage,然后打開多個標簽頁,你會發現數據共享了。關閉所有標簽頁token會立即永久過期(memoryStorage其實就是一個javascript對象而已)。

    1. (function(){
    2. window.memoryStorage = {};
    3. functionisEmpty(o){
    4. for(variino) {
    5. returnfalse;
    6. }
    7. returntrue;
    8. };
    9. if(isEmpty(memoryStorage)) {
    10. localStorage.setItem('getSessionStorage',Date.now());
    11. };
    12. window.addEventListener('storage',function(event){
    13. if(event.key =='getSessionStorage') {
    14. localStorage.setItem('sessionStorage',JSON.stringify(memoryStorage));
    15. localStorage.removeItem('sessionStorage');
    16. } elseif(event.key =='sessionStorage'&& isEmpty(memoryStorage)) {
    17. vardata =JSON.parse(event.newValue),
    18. value;
    19. for(keyindata) {
    20. memoryStorage[key] = data[key];
    21. }
    22. }
    23. });
    24. })();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM