如何结合localStorage和sessionStorage的优势

How to combine advantages of localStorage and sessionStorage

我想在建议使用 HTML5 localStorage. But I don't want anything related to authentication to stay in my storage when the browser is closed which would suggest using HTML5 sessionStorage.

的浏览器选项卡之间共享我的身份验证令牌

Reference 1 related to this topic (click):

That means that you can't share between tabs, for this you should use localStorage

Reference 2 related to this topic (click):

Therefore, it's recommended not to store any sensitive information in local storage

我如何结合选项卡之间的身份验证令牌共享,并仍然确保当浏览器关闭时没有任何内容留在存储中?

其他网站是如何解决这个看似简单的问题的。

实现此目的的一个选择是在页面即将 closed/unloaded 时清理 localStorage,这样存储中就不会留下任何东西。这样一来,localStorage 的行为就像 sessionStorage,因为它会在页面关闭后被删除,但它仍然具有跨选项卡共享数据的 localStorage 的优势.

为此,您可以使用 onbeforeunload 事件:

The beforeunload event is fired when the window, the document and its resources are about to be unloaded.

像这样:

// code here
...

// you have the data in the localStorage
localStorage.setItem("data", "My Data");

// more code here
...

// when the page is about to be unloaded, remove the localStorage data
window.addEventListener("beforeunload", function() {
    localStorage.removeItem("data");
});

但该解决方案太简单了,而且有一个问题:当您关闭一个选项卡时,localStorage 数据将被删除,即使您打开了其他选项卡! (让他们没有任何数据)。为防止在其中一个选项卡关闭时删除数据,您可以跟踪选项卡的数量,并且仅在数字为零时才清除 localStorage

伪代码为:

  1. 页面加载时:
    1. 如果 localStorage 有标签数
      1. 将标签计数增加 1
    2. 否则(不计算制表符)
      1. localStorage 中创建一个包含选项卡数量的变量。
      2. 将该变量设置为 1(当前选项卡)。
  2. 页面卸载时:
    1. 将标签计数减少 1。
    2. 如果选项卡计数为零(这是最后打开的选项卡)
      1. 删除localStorage
      2. 的内容

这是一个非常简单的演示。我添加了一些 console.log 消息,这样你就可以打开控制台并查看每个 load/unload:

发生了什么
<!doctype html>
<html>
    <head>
        <title>Test LocalStorage</title>
    </head>
    <body>
        <h1>Hello World!</h1>
        <div id="tabs">Open tabs = 0</div>
        <script>
            window.addEventListener("load", function() {
                if (!localStorage.tabs) {
                    console.log("Create the tab count");
                    localStorage.setItem("tabs", 1);
                    // restore data in case of refresh, or set to initial value in case of new window
                    localStorage.setItem("data", sessionStorage.getItem("data") || "Initial");
                } else {
                    console.log("Add one tab to the count");
                    localStorage.tabs++;
                }

                document.getElementById("tabs").innerHTML = "Open tabs = " + localStorage.tabs;
            });

            window.addEventListener("beforeunload", function() {
                if (parseInt(localStorage.tabs) == 1) {
                    console.log("Last tab: remove localStorage");
                    // save the data temporarily in the sessionStorage (in case of reload)
                    sessionStorage.setItem("data", localStorage.getItem("data")); 
                    localStorage.removeItem("tabs");
                    localStorage.removeItem("data");
                } else {
                    console.log("There are more tabs open, decrease count by 1");
                    localStorage.tabs--;
                }
            });
        </script>
    </body>
</html>

将该代码复制到页面中,并在多个选项卡中打开它,您将看到选项卡的数量如何增加(如果您重新加载其中一个打开的选项卡,则会更新)。然后关闭它们,最后一个,localStorage中的"data"项将被清除。

我们使用 cookie。

存储有其用途。 但是cookies满足你所有的要求。

  • Cookie 在所有同源选项卡之间共享。您甚至可以指定它们的路径,但默认情况下它们是共享的。

  • Cookies会在浏览器关闭时自动删除,您什么都不用做;这又是默认行为。

  • 可以轻松地使 Cookie 与存储一样安全或更安全。

有时最好的解决方案是最简单的解决方案。 无需重新发明轮子。

Cookie 安全

Session cookie 像 sessionStorage 一样存储在磁盘上(以防浏览器崩溃并需要恢复)。 因此,就本地磁盘而言,它们几乎同样安全 read/write。

在http传输过程中,cookie和存储处理脚本都可能被获取甚至窃取, 所以你必须在这两种情况下都使用 HTTPS。 (这是 the least 你应该做的。)

Cookie 可以配置为 HTTP only, 阻止 JavaScript 访问它, 从而免疫 XSS script and greasemonkey hijacking.

以防身份验证令牌被盗,我们还将每个令牌与机器的用户代理和 ip 相关联。 这可以防止令牌被来自外部网络的人使用。 如果需要,您可以添加更多 content negotiation headers - 并非所有机器人都复制所有 headers.

要获得更高级别的安全性,您可以添加 client side fingerprinting。 这些指纹必须在客户端捕获并通过网络传输,因此它们不是防弹的, 但他们会迫使内部攻击者(与用户在同一网络上的攻击者)跳过另一个圈套。

此时,他们通常会切换到 easier attacks 你无法控制的状态。