带有 JWT 的 REST API 身份验证和 SPA 的 CSRF 保护

信息安全 验证 饼干 csrf 休息 jwt
2021-09-02 06:15:29

我正在开发一个带有 REST 后端的 SPA,并希望拥有基于简单令牌的身份验证。支持 REST 的目标是无状态。我将解释安全模型并尝试参考设计期间做出的决策的所有来源。希望对整个设置发表评论并回答一些具体问题。

抽象的

身份验证将在专用端点(例如 /auth/login)上完成。登录信息将作为 JSON 对象传递。信息将包含用户名和密码。成功登录后,将颁发一个签名的 JWT 令牌。此令牌将用于后续访问 REST API。

应用程序将使用 HTTPS,我控制所有子域。

细节

智威汤逊

  • 包含用户名、发布时间和到期时间
  • 包含有关应用程序内部角色成员资格的声明
  • 包含一个 CSRF 令牌(从加密安全的伪随机生成器随机生成)
  • 使用仅对服务器可用的 HMAC (SHA256) 密钥进行签名

到期

将发出一个具有较短到期时间(例如 30 分钟)的令牌。每次请求(滑动窗口到期)时都会发布一个更新的令牌,并在合理的截止日期(例如 8 小时)内发布。流程如下:

  1. 初始登录请求将发出一个有效期为 30 分钟的令牌
  2. 下一个请求将检查令牌是否已过期。如果过期,访问将被阻止。如果没有,请求将被满足。届时将检查令牌的年龄。

    • 如果年龄在最后期限内(小于 8 小时),将生成更新的令牌,其中包含另外 30 分钟的新到期时间。发行时间与原代币相同。
    • 如果令牌的年龄超过截止日期,则不会生成更新的令牌,用户需要再次登录。

理由:我想保护一个过期时间短的令牌,以防它被泄露。我也不想强迫用户经常重新登录。攻击者需要在小于令牌到期时间的时间范围内请求新令牌。如果攻击者设法做到这一点,他/她可以使用令牌的最长时间由截止日期定义。用户可以在设定的最后期限内保持在线。对于商业申请,8 小时或一天的截止日期就足够了。这个实现是否足够安全?可能的缺点和漏洞是什么?

智威汤逊运输和存储

JWT 将作为 httpOnly cookie 传输到客户端,并将存储在浏览器的 Cookies 存储库中。

基本原理:保护令牌免受 XSS 攻击,如果将令牌保存在 localStorage/sessionStorage 中,则会危及令牌。这是根据本文的建议除了将实现开放给 CSRF 攻击之外,这种方法有什么问题吗?

CSRF 保护

将 JWT 令牌存储在 cookie 中将使实现面临 CSRF 攻击。为了缓解这个问题,实现了双重提交 cookie 方法。CSRF 令牌生成并包含在 JWT 令牌中。此令牌还以对登录请求的响应的 JSON 对象的形式提供给客户端应用程序。应用程序会将 CSRF 存储在 localStorage 中,并将其与自定义标头中的每个请求一起提交。

基本原理:根据参考本文对这个问题的回答,为了有效的 CSRF 保护,有必要将 CSRF 令牌与会话标识/身份验证 cookie 进行加密绑定。如果我在 JWT 中包含一个令牌,它是否被认为与安全会话加密相关?

从概念上讲,你觉得这个实现有什么问题吗?

1个回答

这个实现是否足够安全?可能的缺点和漏洞是什么?

JWT 是自描述的承载令牌。JWT 的两个主要缺点是过时的令牌和无法按需使它们过期。

过时的令牌

如果您的用户角色发生变化,则不会反映在已发行的令牌中。您将需要发行一个全新的。理想情况下,您会过期之前的一个,这将我们带到下一个问题。

没有按需到期

JWT 不能按需过期,因为它们本身是无状态的。解决这个问题的一种方法是 JWT 黑名单,但这会杀死你的服务器的无状态。这也意味着您的用户基本上无法退出您的应用程序,因为您无法按需使令牌无效。

关于短暂的令牌。如果攻击者拥有一个短暂的令牌,他可以查询您的 API 以“让它保持活跃”,只要您允许他(8 小时或 1 天)。

您需要确定这是否足够安全。这完全取决于您愿意做出什么样的取舍。

除了将实现开放给 CSRF 攻击之外,这种方法有什么问题吗?

这完美地工作。我看到很多网站都在使用它。不过,您确实需要担心 CSRF。除非你的 API 只是 JSON。见这里

如果我在 JWT 中包含一个令牌,它是否被认为与安全会话加密相关?

是的,尽管由于我上面描述的按需终止问题,您无法有效地轮换此密钥。这又是一个权衡。

从概念上讲,你觉得这个实现有什么问题吗?

我,觉得你描述的完全有道理。它确实有其缺点和权衡,但只有您知道您需要支持的确切业务案例。如果每个会话没有注销、陈旧的令牌和固定的 CSRF 令牌是可以接受的,那么一切都很好。