【问题标题】:JWT authentication & refresh token implementationJWT 认证和刷新令牌实现
【发布时间】:2017-05-27 14:58:49
【问题描述】:

我正在开发一个具有自己的身份验证和授权机制的 REST 应用程序。我想使用 JSON Web Tokens 进行身份验证。以下是有效且安全的实现吗?

  1. 将开发一个 REST API 来接受用户名和密码并进行身份验证。要使用的 HTTP 方法是 POST,因此没有缓存。此外,在运输时将有 SSL 以确保安全
  2. 在身份验证时,将创建两个 JWT - 访问令牌和刷新令牌。刷新令牌将具有更长的有效期。两个令牌都将写入 cookie,以便在每个后续请求中发送它们
  3. 每次调用 REST API 时,都会从 HTTP 标头中检索令牌。如果访问令牌未过期,请检查用户的权限并相应地允许访问。如果访问令牌已过期但刷新令牌有效,则重新创建新的访问令牌并使用新的过期日期刷新令牌(进行所有必要的检查以确保用户的身份验证权限不会被撤销)并通过 Cookie 发回
  4. 提供一个注销 REST API,它将重置 cookie,因此后续 API 调用将被拒绝,直到登录完成。

这里我对刷新令牌的理解是:

由于刷新令牌的存在,我们可以将访问令牌的有效期保持较短,并经常检查(在访问令牌到期时)用户仍然被授权登录。

如果我错了,请纠正我。

【问题讨论】:

    标签: rest security authentication jwt


    【解决方案1】:

    将开发一个 REST API 来接受用户名和密码并执行 身份验证。要使用的 HTTP 方法是 POST,以便 没有缓存。此外,将有 SSL 以确保安全 过境

    这是大多数人的做法,所以你在这里很好。

    在认证的时候,会创建两个JWT——访问令牌 并刷新令牌。刷新令牌将具有更长的有效期。这俩 令牌将被写入 cookie,以便它们在每个 后续请求

    将令牌存储在 cookie 中本身并不危险,但如果你以某种方式让你的服务器上的 JWT 模块从那里读取它们,你就容易受到 CSRF 攻击,其中任何网页都可以触发用户浏览器发送表单 + 你的站点cookie 到您的服务器,除非您使用 CSRF 令牌。所以通常它们存储在 localStorage 中,并且每次都“手动”添加到请求标头中。

    每次调用 REST API 时,都会从 HTTP 检索令牌 标题。如果访问令牌未过期,请检查权限 用户并相应地允许访问。如果访问令牌已过期 但刷新令牌有效,重新创建新的访问令牌并刷新 具有新到期日期的令牌(进行所有必要的检查以确保 用户进行身份验证的权限不会被撤销)并通过 饼干

    除了 cookie 的危险之外,它似乎是安全的。

    提供一个注销 REST API,它将重置 cookie,因此 在登录完成之前,后续的 API 调用将被拒绝。

    您甚至不需要进行 API 调用,只需清除 cookie 或 localStorage 对象并确保您的客户端不会因丢失令牌而中断。

    express-jwt 模块的标准要求令牌位于其自己的“Authorization: Bearer [Token]”标头中,我强烈建议不要使用 cookie。 localStorage API 一直可用到IE8,所以你应该很好。

    编辑:

    首先,了解 XSS 和 CSRF 攻击之间的区别很重要,因为它们通常被认为是同一件事。

    XSS 是指用户在其他用户的浏览器中在您的域上运行不安全的 JS,当这种情况发生时,localStorage 中的 JWT 或会话中的 JWT 和 cookie 中的 JWT 都不安全。使用 cookie 上的 httpOnly 标志,您无法直接访问它们,但浏览器仍会将它们与 AJAX 请求一起发送到您的服务器。如果发生这种情况,你通常会倒霉。为防止这种情况发生,请确保在将所有用户输入发送到浏览器时对其进行转义。

    如果您使用脚本标签或 iframe 加载第 3 方 JS,除非您小心,否则这可能会危及 localStorage,但我在这方面的工作还不够,无法在这里为您提供帮助。

    CSRF 仅在其他域试图通过让浏览器自动发送 cookie 来向您的服务器发送普通 HTML 表单时。框架通过插入唯一的随机字符串作为隐藏字段并在提交时再次检查它们来防止这种情况。 localStorage 中的 JWT 是安全的,因为每个域都有自己独立的 localStorage 区域。

    但最终这一切都取决于您的服务是否将使用单个域,在这种情况下,httpOnly cookie 将非常安全且易于设置,但如果您想将服务分散到多个域(如 api.domain)上。 com + app.domain.com 或添加一个本机应用程序,您必须将您的 JWT 存储在 localStorage 或其他一些本机存储区域中。

    希望这会有所帮助!

    【讨论】:

    • 感谢您的回答!既然您推荐了本地存储,我很想知道您对本地存储易受 XSS 攻击的看法以及是否有任何安全的解决方案可以防止它。我的理解是现代 Web 框架以保护它们免受 CSRF 攻击的方式处理 cookie。
    • 这个答案完全忽略了OAuth的基本原则
    • @Hans Z. 启发我,哪些原则......而且 OP 也从未提及仅使用 JWT 的 OAuth
    • 我想这就是我的观点:为什么使用与 OAuth 相同的术语(“访问令牌”、“刷新令牌”、“承载令牌标头” - 跨 OP 和答案)并尝试实现类似的目标但是有一个不同的、专有的和不安全的解决方案?只需遵循规范即可。
    • 然后用你的答案告诉 OP JWT 是一个协议,OAuth 是一个框架,他应该考虑构建一个 OAuth 解决方案而不是刻薄...
    【解决方案2】:

    两年前我问过这个问题,也接受了答案。但是,根据我过去两年的经验和学习,我想回答这个问题,以防万一有人偶然发现这个帖子并提出同样的问题。

    问题中提到的方法类似于 OAuth 2.0 的“资源所有者密码凭据”授予类型。但是,我认为最好使用“授权码授予”类型和 Cookie 来存储令牌,而不是浏览器 localStoragesessionStorage。我在this StackOverlow answer中详细说明了我的原因、实现点、安全注意事项和参考。

    【讨论】:

      【解决方案3】:

      和 OP 一样,我一直在使用资源所有者密码授权。

      我从Saptarshi Basu 的另一个answer in a different post 学到了很多东西,我认为任何研究 OAuth 代码流的人都应该看看它,它概述了一种非常可靠的方法来验证 SPA 和资源服务器。它主要依靠您的后端(资源服务器)来处理身份验证提供者作为私有客户端的身份验证。

      但是,我只想补充一点,希望使用 SPA 实现身份验证的人也应该考虑OAuth Code Flow with PKCE。 PKCE 的主要目标是允许公共客户端(例如 SPA)直接通过身份验证提供者进行身份验证。 PKCE 添加的所有内容是,当 SPA 应用程序启动身份验证时,当用户通过身份验证时,会向身份验证提供程序发送一个散列值。在用户通过授权提供者进行身份验证后,它会将用户重定向回带有该散列值以及授权代码的 SPA。现在,对于 SPA 调用身份验证提供程序以交换令牌代码的下一部分,它必须提供最初用于创建散列值的密钥,而不是提供客户端机密。这种机制保证了代码不会被截获代码的人使用,并且 SPA 不需要像服务器端应用程序那样存储客户端密码。

      现在我唯一不确定的是,在技术上更安全的服务器端身份验证使用标准代码流而不使用 PKCE 或 SPA 直接使用 PKCE 身份验证?目前我可以在网上找到的大多数资源都描述并推荐了后者。但是我觉得让私有服务器端客户端处理身份验证(如Saptarshi Basu 所述)可能仍然更安全。我也很想听听他对此的看法。

      【讨论】:

      • 同意。 PKCE 是可行的方法,Okta、Auth0 等现代解决方案使用 PKCE。当我写其他答案时,我不知道 PKCE。为了完整起见,我会更新它们。感谢您指出。
      【解决方案4】:

      这里我对刷新令牌的理解是:

      由于刷新令牌的存在,我们可以将访问令牌的有效期保持较短,并经常检查(在访问令牌到期时)用户仍然被授权登录。

      如果我错了,请纠正我。

      假设您正在谈论在 OAuth 中使用 JWT 作为 Bearer-token(我强烈建议您遵循 OAuth 2.0 协议),这是正确的。

      在您的 JWT 中添加一个额外的 auth-time(身份验证时间戳)声明,您甚至可以删除第二个令牌并将您的访问 - 作为刷新令牌发送(如果令牌有效且授权时间在允许的范围内)...但是当然,遵循标准也很好;)

      无论如何,在将 JWT 用作刷新令牌之前,您应该考虑一些额外的方面(这些方面往往会变得困难,甚至违背 JWT 的基本理念),因为这基本上意味着您引入了长期存在的 JWT:

      • 您是否需要强制用户注销/主题撤销令牌(例如,如果用户被识别为欺诈)?
      • 您是否需要撤销特定令牌(例如,如果用户丢失设备)?
      • ...

      根据您的用例,您应该考虑所有可能的影响,长寿命令牌通常需要您在服务器端引入某种状态(例如,允许撤销/列入黑名单)。请记住,JWT 概念的美丽和安全性在于 JWT 是短暂的。

      【讨论】:

        猜你喜欢
        • 2020-05-20
        • 2014-12-22
        • 2021-10-27
        • 1970-01-01
        • 2018-09-29
        • 1970-01-01
        • 2016-03-05
        • 2016-06-25
        • 2020-09-25
        相关资源
        最近更新 更多