JavaScript >> Javascript 文檔 >  >> JavaScript

邁向更安全的客戶端數據存儲

去年,我開始深入研究由於 HTML5 而出現的各種客戶端數據存儲替代方案。其中包括 sessionStorage , localStorage 和客戶端數據庫。雖然我很高興看到朝這個方向發展,但我對一些結果並不滿意。我圍繞 sessionStorage 開始了我的探索 ,儘管它受到嚴格限制,但我認為它非常有用,並且很好地解決了一些與客戶端存儲數據相關的安全問題(有關更多信息,請參閱完整的博客文章)。我不是,現在仍然不是,將網絡上的 SQL 作為結構化數據存儲解決方案的粉絲,我很高興看到 Microsoft 和 Mozilla 的人們朝著另一個方向發展。

話雖如此,我開始查看 localStorage .確實,這是一個偉大的想法:一個由所有瀏覽器窗口(或選項卡)共享並綁定到特定域的持久存儲區域。我知道由於跨進程數據管理的複雜性,瀏覽器供應商對此功能有很多不喜歡的地方,但我對 API 的問題與人們對數據的控制力有多大有關。

問題

localStorage中的數據存儲機制存在兩大問題 :

  1. 數據存儲在未加密的磁盤上。這意味著任何有權訪問計算機的人都可以訪問該數據。
  2. 數據會一直保留在磁盤上,直到網站將其刪除或用戶明確告訴瀏覽器將其刪除。這意味著數據可能會永久保留在磁盤上。

這些都是問題,因為它們都增加了數據被非預期對象檢查的可能性。

假設我正在運行一個主要的 webmail 客戶端,並希望通過將有關客戶電子郵件的信息存儲在 localStorage 中來提高站點的性能。這樣,您可以加快網站的啟動時間,並且只下載新的電子郵件信息。 (順便說一句,這是一個非常糟糕的主意,請不要這樣做。)現在假設您註銷並關閉瀏覽器。您的電子郵件數據仍保存在磁盤上,因為您離開時 webmail 客戶端並未將其刪除。如果是您的個人筆記本電腦,這沒什麼大不了的;如果它是網吧裡的一台電腦,那將是一筆巨大的交易。想像一下,如果在那家網吧裡,另外 20 個人最終使用同一台計算機訪問同一個網絡郵件客戶端,並且他們的所有數據最終都存儲在磁盤上。大問題。

您可能會問自己,“加密數據不能解決這個問題嗎?”是和不是。您可以建議 localStorage 在寫入磁盤時始終加密數據,但最終會成為標準加密算法和標準密鑰。雖然這會為數據提供一點護城河,但也很容易弄清楚瀏覽器在密碼和密鑰方面的選擇,迫使瀏覽器供應商要么在如何將數據加密到磁盤或更改數據存儲方面非常聰明方法頻繁。 (想像一下,如果有人發現並在網上發布了詳細信息,那麼一定會急於更新受影響的瀏覽器以確保數據安全。)

不要誤會我的意思,對於公開可用的數據,沒有理由不使用 localStorage .但是對於任何對用戶來說甚至是遠程個人的東西,您都將個人數據放置在一個太容易訪問的區域中。

解決方案

我不認為 localStorage 有明確的前進道路 使其更安全。它就在那裡,人們正在使用它,現在更改 API 將是一個巨大的問題。當我在 Mozilla 數據存儲峰會上提出這些問題時,我最常聽到的是,“如果你能想出解決這個問題的方法,寫下來,我們再談。”於是我坐下來寫了一個名為 SecureStore 的關於在瀏覽器中安全鍵值存儲的提案。

該提案基於一些安全意識強的公司共享的簡單概念:

  1. 用戶數據不應存儲在未加密的磁盤上。
  2. 即使用戶數據以加密方式存儲,公司也必須控制加密算法和密鑰。
  3. 即使經過加密,用戶數據也不應該永遠保存在磁盤上。

這些規則傳統上適用於服務器和服務器端緩存,但似乎足夠合乎邏輯,可以擴展到瀏覽器中的客戶端數據存儲。

我試圖讓大部分 API 與現有的客戶端數據存儲 API 相似,以免引入完全不同的東西。但是,一個很大的區別是訪問存儲對象的方式。為此,您必須調用 openSecureStorage() 方法並傳入加密密碼、base64 編碼的密鑰和將接收存儲對象的回調函數:

window.openSecureStorage("mystorage", window.AES_128, key, function(storage){
   //use storage object
});

這段代碼將做兩件事之一。如果名為“mystorage”的存儲區域不存在,則將創建該存儲區域,並在向其寫入數據時使用給定的密碼和密鑰。一個空的 SecureStorage 然後將對像傳遞給回調函數。如果存儲區確實存在,則打開它,解密內容,並在 SecureStorage 上提供數據 目的。請注意,存儲區域與域相關聯,並且特定域的存儲區域數量沒有限制(僅對域可以使用的空間總量有限制)。

一旦你有一個 SecureStorage 對象,您可以使用 length 屬性來確定有多少個鍵值對可用,所有標準的存儲方法也都有:

  • getItem(key) – 檢索給定鍵的值,如果鍵不存在,則檢索 null。
  • setItem(key, value) – 設置給定鍵的值。
  • removeItem(key) – 完全刪除密鑰。
  • key(position) – 返回給定數字位置的值的鍵。
  • clear() – 刪除所有鍵值對。

請注意,您必須使用 getItem() , setItem() , 和 removeItem() 用於操作鍵;鍵不會自動成為 SecureStorage 上的屬性 目的。除了那個區別,你使用 SecureStorage 對象與 sessionStorage 相同 或 localStorage .此外,密鑰和值都在磁盤上加密。

稱為 setExpiration() 的附加方法 存在於 SecureStorage 上 對像也是。此方法允許您傳入 Date 指示何時應刪除數據的對象。例如:

window.openSecureStorage("mystorage", window.AES_128, key, function(storage){

    storage.setItem("username", "Nicholas");
    storage.setItem("super_secret_value", "unicorn");

    //set expiration for a year from now
    var expires = new Date();
    expires.setFullYear(expires.getFullYear() + 1);

    storage.setExpiration(expires);
});

您可以多次設置過期日期以延長數據的使用壽命。

該 API 特意變得有點通用,以便可以輕鬆添加額外的加密密碼,並允許開發人員控制從何處生成加密密鑰。在某些情況下,這可能由服務器完成,或者可能由瀏覽器供應商將來創建的一些尚未定義的 API 完成。關鍵是隨著網絡技術的不斷發展,可以輕鬆擴展。

為什麼?

關於這個提議,我得到的最常見的問題之一是,創建一個可以與 localStorage 結合使用的通用 JavaScript 加密 API 是否比創建一個全新的數據存儲解決方案更好。首先,我會說我認為原生 JavaScript 加密 API 會很棒,我完全贊成。然而,我希望避免的是需要編寫這樣的代碼:

//write name and value so they're both encrypted
localStorage.setItem(AES.encrypt("username", key), AES.encrypt("Nicholas", key));

//retrieve the encrypted username
var username = AES.decrypt(localStorage.getItem(AES.encrypt("username", key)), key);

我不確定這對你來說是否像對我一樣混亂,但似乎這是一種足夠常見的模式,擁有一個阻止我們編寫如此可怕的代碼的本機實現是個好主意。

讓我們把它變成現實

完整提案還有很多細節,但我想在這篇文章中強調一些亮點。我已經從至少一個瀏覽器供應商那裡收到了關於這個提議的積極反饋,現在我需要幫助來實現這一點。我真正需要的是更多來自人們的反饋。我已經挑選了同事的大腦,現在我想向公眾開放它。我感興趣的:

  • 實施者:這個 API 有什麼地方讓它難以實施嗎?
  • Web 開發人員:您有一個可以解決的用例嗎?
  • Web 開發人員:對於 API,您有什麼想要改變的嗎?
  • 大家:還有別的嗎?

如果您是開源瀏覽器的貢獻者,我也在尋找有興趣製作此 API 以在 WebKit 和/或 Gecko 中使用的原型的人。如果您有興趣或有其他不想公開發布的反饋,請隨時與我聯繫。


Tutorial JavaScript 教程
  1. JavaScript 的多種風格

  2. 反應模板 - 節點

  3. 使用什麼來創建在 apache2 上運行的蜂鳴器 webapp

  4. 對話框變得簡單!

  5. Redux 操作不是設置器

  6. 如何使用 NgRx 處理不可序列化的數據

  7. 我如何用 0 美元構建 Web 開發挑戰網站(你也可以!)

  1. 關於 NPM 包和 Bundle 大小的影響

  2. React Live Code Challenge...我學到了什麼

  3. 如何使用 Socket.IO 並構建您的第一個多人遊戲!

  4. 冒名頂替綜合症已經開始...

  5. Javascript電話號碼驗證

  6. 油門每個等待週期最多執行一次功能,對嗎?

  7. 如何從 Mongoose 的集合中排除一個特定字段?

  1. 自動更新 GitHub 項目的依賴關係

  2. 使用 Netlify 函數將聯繫表單添加到靜態站點

  3. Vanilla JavaScript 為我們的畫布元素著色🌈

  4. 萬物反應