带有SPA且无需服务器的JWT

Ita*_*Ale 5 javascript security jwt single-page-application

该应用程序是一个SPA,该SPA托管在静态存储上(虽然与S3相似,尽管不是S3,但在概念上类似于S3),并且根本没有后端服务器。假设这是https://static.example.com/app.html

用户访问页面时,他们可以通过外部提供程序(如Auth0和Azure AD)进行身份验证。它们完成了身份验证流程,并带有id_tokenURL片段上的发送回SPA 。例如,https://static.example.com/app.html#id_token=XX。这id_token用于调用在Bearer授权标头中传递的外部API服务器。

问题是将JWT存储在客户端的位置。

  1. 众所周知,将JWT存储在其中sessionStorage可能会导致令牌被XSS攻击(或在依赖项中添加恶意代码等)窃取。
  2. 推荐的方法是将JWT存储在设置为HttpOnly或其中至少一部分的 Cookie中(请参阅“ Cookie拆分”部分)。但是,在我的情况下,这是不可行的,因为没有后端服务器,并且经过身份验证的用户将直接重定向到SPA,因此无法创建HttpOnlyCookie。OWASP建议使用
    此方法的一种变体:使用“指纹cookie”。由于我无法设置Cookie,因此存在相同的问题。HttpOnly
  3. 例如,Auth0文档建议的另一种方法是将JWT保留在内存中。尽管这应该可以防止大多数(如果不是全部?)XSS攻击被盗,但这是不切实际的,因为会话将限于当前选项卡,并且无法在页面重新加载后幸存下来。

我看到了两种不同的选择,它们都有严重的或潜在的严重缺陷:

  1. sessionStorage假设以XSS攻击(或通过NPM注入恶意依赖关系)可能导致会话被盗的风险,以任何方式存储令牌。可以通过将令牌的寿命设置得较短(例如1小时)来缓解这种情况。虽然我正在使用的应用程序没有存储关键信息(它不是银行信息或类似信息),但允许通过XSS窃取会话的代码错误并不好。
  2. 实现一个后端服务器以将身份验证流移到那里,甚至可以用会话令牌完全替换JWT。但是,这将使应用程序不再是静态的,这是不可取的。
  3. (由于用户体验差,排除了将JWT保留在内存中的第三个选项)

我想念什么?

Gab*_*yel 3

安全性是一种妥协——您可以选择接受 XSS 风险,或者承担后端服务器的负担以获得更高的安全性,或者牺牲用户体验以获得可能介于两者之间的安全级别。你不可能拥有一切。

一种常见的解决方案是在 sessionStorage 中使用非常短暂的令牌,并使用 httpOnly cookie 供身份提供者在需要时获取新令牌。这种窃取会话令牌的方式为攻击者提供的价值较小,并且由于 XSS 需要用户交互,因此攻击者有时可能很难获得新的令牌(或者很容易,具体取决于 XSS 所在的位置)。此外,此解决方案需要更优雅的错误处理,并导致代码稍微复杂一些。