javascript - 我是否必须将 token 存储在 cookie、localstorage 或 session 中?

标签 javascript jwt

我正在使用 React SPA、Express、Express-session、Passport 和 JWT。
我对存储 token 的一些不同客户端存储选项感到困惑:Cookies、Session 和 JWT/Passport。

token 是否必须存储在 cookie 中,即使我可以将它们存储在 req.sessionID 中?

许多网站使用 cookie 来存储购物车 token 。到目前为止,我已经根据 session ID 存储了购物车数据,而没有添加任何 cookie。

So when users visit my website, I will match it with their req.sessionID and then retrieve the data in the database like shopping carts and user session.



我需要存储cookies吗?我可以通过 req.sessionID 访问它以获取所需的数据。

第二个

我已使用 passport-google-oauth20 进行身份验证.我成功登录后,数据被保存到 session 中。并将其发送给客户端,我必须通过 URL 查询 ?token='sdsaxas' 发送它.

in this case I get a lot of difference of opinion. someone saved it into local storage and someone saved it into cookies by converting it to a token using JWT.


 jwt.sign(
        payload,
        keys.jwt.secretOrPrivateKey, 
        {
            expiresIn:keys.jwt.expiresIn // < i dont know what is this expired for cookies or localstorage ?
        }, (err, token) => {

            res.redirect(keys.origin.url + "?token=" + token);
        });

我确实可以使用 sessionID(没有 cookie 或 localstorage)存储与 session 相关的所有内容吗?

由于我使用 React SPA,因此只能通过执行一次或每次页面刷新并检索数据然后保存到 redux 中。

最佳答案

这个答案基于无状态方法,因此它没有讨论传统的 session 管理
你问了两个完全不同的问题:

  • 购物车 - 与业务功能更相关
  • OAuth 2 & JWT - 与安全和认证相关

  • 作为电子商务网站的用户,我希望我在上类途中从移动设备添加到购物车中的任何商品都应该在我回家后从 PC 登录网站时出现在购物车中。因此,购物车数据应保存在后端数据库中并链接到我的用户帐户。
    在使用 OAuth 2.0 进行身份验证时,JWT 访问 token 和/或刷新 token 需要存储在客户端设备中的某个位置,以便一旦用户通过提供登录凭据对自己进行身份验证,他就不需要再次提供他的凭据浏览网站。在这种情况下,浏览器本地存储、 session 存储和 cookie 都是有效的选项。但是,请注意,此处的 cookie 未链接到服务器端的任何 session 。换句话说,cookie 不存储任何 session ID。 cookie 仅用作访问 token 的存储,访问 token 随每个 http 请求传递到服务器,然后服务器使用数字签名验证 token 以确保它没有被篡改和过期。
    尽管访问和/或刷新 token 的所有三个存储选项都很流行,但如果以正确的方式使用,cookie 似乎是最安全的选项。
    为了更好地理解这一点,我建议您阅读 thisthis以及 OAuth 2.0 规范。
    2019 年 2 月 16 日更新
    我之前说过 cookie 似乎是最安全的选项。我想在这里进一步澄清这一点。
    我认为浏览器的原因localStoragesessionStorage没有为存储 auth token 提供足够的安全性如下:
  • 如果发生 XSS,恶意脚本可以轻松地从那里读取 token 并将它们发送到远程服务器。在那里,远程服务器或攻击者在冒充受害用户方面没有问题。
  • localStoragesessionStorage不跨子域共享。因此,如果我们有两个 SPA 在不同的子域上运行,我们将无法获得 SSO 功能,因为组织内的另一个应用程序无法使用一个应用程序存储的 token 。有一些解决方案使用 iframe ,但这些看起来更像是变通方法而不是好的解决方案。而当响应头 X-Frame-Options用于避免点击劫持攻击 iframe , 任何带有 iframe 的解决方案毫无疑问。

  • 但是,可以通过使用指纹(如 OWASP JWT Cheat Sheet 中所述)来减轻这些风险,而指纹又需要一个 cookie。
    指纹的想法是,生成加密强的随机字节串。然后原始字符串的 Base64 字符串将存储在 HttpOnly 中。 , Secure , SameSite带有名称前缀的 cookie __Secure- .应根据业务需求使用域和路径属性的正确值。字符串的 SHA256 哈希值也将在 JWT 的声明中传递。因此,即使 XSS 攻击将 JWT 访问 token 发送到攻击者控制的远程服务器,它也无法发送 cookie 中的原始字符串,因此服务器可以基于 cookie 的缺失拒绝请求。 cookie 是 HttpOnly XSS 脚本无法读取。
    因此,即使我们使用 localStoragesessionStorage ,我们必须使用 cookie 来确保它的安全。最重要的是,我们添加了如上所述的子域限制。
    现在,使用 cookie 存储 JWT 的唯一问题是 CSRF 攻击。由于我们使用 SameSite cookie,CSRF 得到缓解,因为跨站点请求(AJAX 或仅通过超链接)是不可能的。如果该网站在任何旧浏览器或其他不支持的不太流行的浏览器中使用 SameSite cookie,我们仍然可以通过额外使用具有加密强随机值的 CSRF cookie 来缓解 CSRF,这样每个 AJAX 请求都会读取 cookie 值并将 cookie 值添加到自定义 HTTP header 中(除了不应该这样做的 GET 和 HEAD 请求)任何状态修改)。由于CSRF由于同源策略无法读取任何内容,并且它基于利用POST,PUT和DELETE等不安全的HTTP方法,因此该CSRF cookie将减轻CSRF风险。所有现代 SPA 框架都使用这种使用 CSRF cookie 的方法。提到了 Angular 方法 here .
    此外,由于 cookie 是 httpOnlySecured , XSS 脚本无法读取。因此,XSS 也得到了缓解。
    可能还值得一提的是,通过使用适当的 content-security-policy 可以进一步减轻 XSS 和脚本注入(inject)。响应头。
    其他CSRF缓解方法
  • 状态变量(Auth0 使用它) - 客户端将生成并通过每个请求传递一个加密的强随机随机数,服务器将与其响应一起回显,允许客户端验证随机数。在 Auth0 doc 中有解释.
  • 始终检查引用 header 并仅在引用域是受信任域时才接受请求。如果引用 header 不存在或域未列入白名单,只需拒绝请求即可。使用 SSL/TLS 时通常会出现引用。登陆页面(主要是信息性的,不包含登录表单或任何安全内容)可能有点放松,并允许缺少引用 header 的请求。
  • 应在服务器中阻止 TRACE HTTP 方法,因为这可用于读取 httpOnly曲奇饼。
  • 另外,设置 header Strict-Transport-Security: max-age=; includeSubDomains 只允许安全连接,以防止任何中间人覆盖来自子域的 CSRF cookie。
  • 关于javascript - 我是否必须将 token 存储在 cookie、localstorage 或 session 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54258233/

    相关文章:

    javascript - 正确删除匿名函数事件处理程序

    java - 在 JWT 身份验证设置中处理刷新 token 的最可扩展/最安全的方法是什么?

    flask - 后端访问和刷新 token 实现、安全和性能问题

    javascript - 使用视频源作为 Canvas 视频轨道的 OpenTok 问题 - Google Chrome 66

    javascript多维数组?

    jwt - 没有 AuthHttp 提供者! Angular2-Jwt 提供程序问题

    javascript - Google Cloud Functions 部署问题

    Azure AD token 落后 5 分钟

    javascript - 通过 CDN 或 minifiy/concat 加载资源并为自己服务?

    javascript - 在 Vue.js 2 中将 Prop 作为初始数据传递的正确方法是什么?