繁体   English   中英

JWT 身份验证和刷新令牌实现

[英]JWT authentication & refresh token implementation

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

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

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

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

如果我错了,请纠正我。

将开发一个 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 模块的标准期望令牌位于其自己的“授权:承载 [令牌]”标头中,我强烈建议使用 cookie。 localStorage API 一直可用到IE8,所以你应该很好。

编辑:

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

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

如果您使用脚本标签或 iframe 加载 3rd 方 JS,除非您小心,否则这可能会损害 localStorage,但我还没有足够的工作来帮助您。

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

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

希望这可以帮助!

两年前我问过这个问题,也接受了答案。 但是,根据我过去两年的经验和学习,我想回答这个问题,以防有人遇到同样的问题。

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

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

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

如果我错了,请纠正我。

假设您正在谈论在 OAuth 中使用 JWT 作为不记名令牌(我强烈建议遵循 OAuth 2.0 协议),那就对了。

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

无论如何,在使用 JWT 作为刷新令牌之前,您应该考虑某些其他方面(往往会变得困难,甚至与 JWT 的基本思想背道而驰),因为这基本上意味着您引入了长期存在的 JWT:

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

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

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

我在另一篇文章中Saptarshi Basu的其他答案中学到了很多东西,我认为任何研究 OAuth 代码流的人都应该看看它,它概述了一种非常可靠的 SPA 和资源服务器身份验证方法。 它主要依靠您的后端(资源服务器)来处理身份验证提供程序作为私人客户端的身份验证。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM