为什么 auth0 建议不要将令牌存储在 localStorage 中?

Why is auth0 recommending not to store tokens in localStorage?

Auth0 提供了广泛的资源列表,描述了身份验证的最佳实践。其中有源源不断的建议不要使用 localStorage 作为存储 (JWT) 令牌的手段。

我发现这些点有几个问题:

所以我完全同意OWASP的建议,不要在localStorage中存储敏感数据,我永远不会想到存储信用卡号或密码甚至个人数据那里。但这只是因为这些东西会让攻击者扩大攻击范围(访问银行账户、尝试在其他应用程序中重用用户密码等)。但是我很难看到 accessTokens 是如何受此影响的。

虽然我不太了解 Auth0 的实现、功能和设计决策,但根据我对 OAuth2 和安全性的一般理解,我可以尝试将这些点联系起来。


单个建议本身并不能提供足够的安全性或所需的功能,但当与其他相关建议结合使用时,我们可以达到所需的安全性和行为级别。

让我们来看看你提出的观点。

From my perspective accessing the tokens itself doesn't extend the scope of attack. If the attacker has control over the victim's browser they can execute the calls, using the token, from the affected browser itself

localstorage 的问题是:

  1. localStoragesessionStorage 未在 sub-domains 之间共享。这是 SSO 功能的显示阻止程序(有一些解决方案使用 iframe,但那些看起来更像是变通方法而不是好的解决方案。当响应 header X-Frame-Options 用于避免点击劫持时使用 iframe 进行攻击,使用 iframe 的任何解决方案都是不可能的)

  2. XSS 可以将访问 and/or 刷​​新令牌发送到攻击者控制的远程服务器,从而允许攻击者冒充用户

注意:第 2 点中提到的漏洞可以通过使用 OWASP 中提到的需要 cookie 的 Sender Constrained Access Tokens approach where the client has to prove that they indeed own the token. Another alternative is the fingerprint approach 来缓解。然而,似乎 Auth0 没有实现这些。因此,避免localstorage的建议是有道理的。

Auth0 recommends using auth0.getTokenSilently() from their SDK to obtain the token, but as far as I see, there shouldn't be any reason why attacker couldn't call this method themselves

正确。这就是为什么

  1. 我们首先需要遵循 OWASP XSS prevention guidelines 来降低 XSS 的风险。
  2. 此外,getTokenSilently() 方法要求您在仪表板的 API 设置中启用 Allow Skipping User Consent。虽然我没有看到这方面的具体指南,但我认为如果您将令牌存储在 cookie 中,则不需要启用此选项,从而消除了滥用该方法的任何可能性。

The only way that I know where XSS wouldn't be able to access the tokens is basically using httpOnly cookies, but that creates new vectors by itself (CSRF) and still wouldn't prevent attackers from calling the api from within the affected browser

没错。但是您可以通过以下一种方法或多种方法的组合来缓解这种情况:

  1. 使用 SameSite cookie。请参阅文档 here。如果浏览器不支持 SameSite cookie,请按照下面的另一种方法
  2. 状态变量(Auth0 使用它)- 客户端将生成并随每个请求传递一个加密的强随机随机数,服务器将回显该随机数及其响应,允许客户端验证该随机数。 Auth0 doc.
  3. 中对此进行了解释
  4. 使用具有加密强随机值的 CSRF cookie,以便每个 AJAX 请求读取 cookie 值并在自定义 HTTP header 中添加 cookie 值(GET 和 HEAD 请求除外,它们是不应该做任何状态修改)。由于 CSRF 由于同源策略而无法读取任何内容,并且它基于利用 POST、PUT 和 DELETE 等不安全的 HTTP 方法,因此此 CSRF cookie 将减轻 CSRF 风险。所有现代 SPA 框架都使用这种使用 CSRF cookie 的方法。提到了 Angular 方法 here
  5. 始终检查引荐来源 header 并仅在引荐来源是受信任的域时才接受请求。如果 referer header 不存在或 non-whitelisted 域,则简单地拒绝该请求。使用 SSL/TLS 时通常会出现引荐来源网址。着陆页(主要是信息性的,不包含登录表单或任何安全内容可能有点宽松,并允许缺少引荐来源网址的请求header
  6. 应在服务器中阻止 TRACE HTTP 方法,因为它可用于读取 httpOnly cookie
  7. 此外,将 header Strict-Transport-Security: max-age=<expire-time>; includeSubDomains​ 设置为仅允许安全连接以防止任何 man-in-the-middle 覆盖来自 sub-domain
  8. 的 CSRF cookie