我正在我的应用程序中实现 JWT,我想让它们尽可能安全。我将列出我正在计划的所有内容,非常感谢有关此实施安全性的任何建议。这是我的网站,我可以完全访问它的各个方面,包括前端和后端。
这将是一个 SPA,使用 API 访问后端。我使用 JWT 来保存每个 API 命中的数据库调用。
智威汤逊
JWT 存储在access_token
cookie 中。它们首先被签名,然后使用jose-jwt加密。签名算法是HS256,加密是DIR。它们包括用户 ID、过期exp
声明和其他几个自定义声明。JWT 在 30 分钟后过期,JWT cookie 在 7 天后过期。
(简洁版本):
- 存储在 cookie 中的 JWT
- JWT 包含用户 ID
- JWT 签名然后加密
- JWT
exp
声明将在未来设置为 30 分钟 - JWT cookie 设置为在未来 7 天后过期
CSRF 保护
JWT 包含一个cst
存储随机生成的 CSRF 令牌的声明。CSRF 令牌在登录时和发出新 JWT 时在响应正文中发送。CSRF 令牌存储在浏览器的 localStorage 中。它随每个请求一起发送,并根据 JWT 中的值进行验证。
(简洁版本):
- JWT 包含一个随机生成的 CSRF 令牌
- 登录时发送并存储在 localStorage 中的 CSRF 令牌
- 在所有请求的请求头中发送的 CSRF 令牌
- 标头 CSRF 令牌与 JWT 中的 CSRF 令牌相比
刷新令牌
由于 JWT 在 30 分钟后到期,因此有必要对其进行刷新。JWT 包含一个rfs
存储随机刷新令牌的声明。此刷新令牌也存储在数据库中(与用户分开的表以允许多个会话)。如果 JWT 已过期(基于其exp
声明),则检查数据库以确保用户仍然有效(例如,未删除帐户、未更改密码等)。如果用户有效,则验证刷新令牌并生成新的 JWT/CSRF 令牌并在响应中传回。如果用户无效,access_token
则返回一个任意值,如0
,并将其过期设置为过去,以便浏览器将其清除。CSRF 令牌传回为空,因此将从 localStorage 中清除。用户的所有刷新令牌都从数据库中清除。
(简洁版本):
- 如果 JWT 过期,检查用户数据库以验证用户是否仍然有效
- 如果有效:
- 将刷新令牌与 DB 进行比较(假设它与其余部分匹配)
- 生成新的刷新令牌,覆盖数据库中的先前值
exp
用新日期重新签发 JWT- 将刷新令牌传回并存储在 localStorage
- 如果无效:
- 通过 a) 设置为无效值,b) 将过期设置为过去,清除 JWT cookie
- 告诉浏览器清除 localStorage CSRF 令牌
- 从数据库中清除用户的所有刷新令牌
快速而肮脏的 TL;DR
- 登录后,将随机 CSRF 令牌添加到 JWT。
- 在响应正文中将相同的 CSRF 令牌发送回客户端。
- 将 CSRF 令牌存储在 localStorage 中。
- 在 JWT 中包含刷新令牌。
- 将 JWT cookie 设置为 1 周后过期。
- 将 JWT exp 声明设置为 30 分钟。
- 如果 JWT 声明已过期,请针对 DB 验证刷新令牌以确保用户仍然有效。
- 如果用户有效:
- 使用新的 CSRF 令牌和新的刷新令牌发出更新的 JWT。
- 将 JWT cookie 的到期时间设置为未来一周。(基本上是重新发行cookie)
- 在响应正文中发送新的 CSRF 令牌,覆盖现有的 localStorage 值。
- 如果用户无效:
- 返回具有相同名称但没有内容的 JWT cookie。
- 将 cookie 过期时间设置为过去的任意日期。
- 告诉浏览器清除 localStorage 值。