Bootstrap

避免将 JWT 存储在 localStorage 中

在文章中《》介绍过使用 的好处,如无状态、自我存储等, 也提到过将 存储在 中的方式。可能有人会疑问,使用了 Token 为什么还用 ,可以把 存储在本地,如 。

看到很多文章介绍将 JWT 存储在 中,事实上,个人觉得建议最好不要。这就是将敏感信息存储在 中,对于安全问题来说是个挑战,对于客户端的行为在安全问题上多数是不可靠的。

先简单介绍一下本地存储。

本地存储

是 HTML5 的一项新特征,它基本上允许 Web 开发人员使用 JavaScript 在用户的浏览器中存储想要的任何信息,十分简单。

在操作上, 只是一个可以添加或删除数据的 JavaScript 对象,下面是一段 操作的示例代码,该代码片段将创建一个指定 的 数据,并可以为其更新、删除数据。

export const useStorage = (
    valKey = "authorization",
    keyPrefix = "DevPoint"
) => {
    const localKey = `${valKey}.${keyPrefix}`;
    const save = (data) => {
        window.localStorage.setItem(localKey, JSON.stringify(deepCopy(data)));
    };
    const get = () => {
        const localData = window.localStorage.getItem(localKey);
        if (localData && localData !== "") {
            return JSON.parse(localData);
        } else {
            return false;
        }
    };
    /**
     * 清除 localStorage 中 valKey 的值
     */
    const clear = () => {
        window.localStorage.setItem(localKey, "");
    };
    return {
        save,
        get,
        clear,
    };
};
// 清除所有的 localStorage
export const cleanAll = () => {
    window.localStorage.clear();
};

打开浏览器开发工具,在控制台窗口的 的标签页下看到,左侧的 可以看到,如下图所示:

是一个纯 JavaScript 对象。如果正在构建一个单页面站点,使用 之类的东西意味着网页可以独立于任何 Web 服务器运行,只需要浏览器存储空间,而无需在服务器中存储任何数据。

此外, 的好处是大小限制:像 一般是 的大小限制,而 在所有主流浏览器中至少 的数据存储。因此现在也越来越多的 Web 应用使用 来存储一些数据。

安全问题

尽管使用简单,但在安全问题上,没有任何的保护措施,这就意味着敏感信息存储在 会带来安全问题。

将任何敏感信息存储在 中相当于在互联网中发布了这些信息。 设计的目的是为浏览器增加本地存储机制,被设计为简单的 存储,开发人员可以使用它来构建稍微复杂的单页应用程序。

当将敏感信息存储在 中时,实际上是在使用世界上最危险的东西 将最敏感的信息存储在有史以来最糟糕的保险库中,绝对不是一个好注意

如果攻击者可以在您的网站上运行 JavaScript,他们就可以检索您存储在 中的所有数据并将其发送到他们自己的域中。这意味着存储在 中的敏感信息都有可能受到损害。

当然可能有足够的信息认为 Javascipt 无法在您的站点中运行,但是如果您的站点包含来自域外源的第三方 JavaScript 代码,例如一些第三方脚本库的CDN源:

  • bootstrap 源

  • jQuery

  • 广告脚本

  • 谷歌分析链接

  • 跟踪脚本

  • ...

一旦出现第三方脚本库被攻击了就会带来安全上的威胁,或许不曾使用第三方脚本库,又或者第三方脚本库绝对安全。

如果需要考虑所有可能的场景,为了降低安全事故的风险,建议尽量不要在 中存储任何重要的敏感信息。

JWT 本质上与 在功能上相同,一旦知道 JWT 就相当于知道了用户名和密码。

如果攻击者可以获得 JWT 副本,就可以神不知鬼不觉的伪造请求向网站发出请求,因此建议不要将敏感信息存储在 中。

存储在 HttpOnly Cookie

本文只是介绍了将 JWT 存储在 的不好,不推荐这样使用。

建议的方式是将JWT存储在 中,优点是不需要在 JavaScript 代码中处理 , 后续请求中都会自动跟上 Token 信息的 。

再者 Cookie 的 HttpOnly 标签是防御 的解决方案之一,因为 在简单的条件下阻止客户端(JavaScript)访问 。如果再将 标志设置为 ,则只会在安全或加密的网络中使用 ,从而增加其安全性。

虽然上面的方式可以防御 ,但还存在另一个威胁即跨站请求伪造(CSRF),可以采用 CORS 白名单机制,并且 CSRF 令牌 与 JWT 一起使用。

但是在某些情况下,例如当 API 被移动应用程序使用并且它需要 标头而不是 时,或者当需要使用同一个 JWT 向多个后端发出 HTTP 请求时,把 JWT 存在 中的方案就更方便。

还有一点 Cookie 存储的大小为 4KB ,因此在使用这个方案的时候需要注意 JWT 的大小。如果 JWT 超过了 就不适合使用 Cookie 存储 JWT的方案。

总结

JWT 是一个非常流行的标准,可以使用签名来信任请求,并在各方之间安全的交换信息。在实际项目开发中,建议避免将 JWT 存储在 中,而是存储在 。