为什么 auth0 建议不要在 localStorage 中存储令牌? [英] Why is auth0 recommending not to store tokens in localStorage?

查看:37
本文介绍了为什么 auth0 建议不要在 localStorage 中存储令牌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

  • 强烈假设 JWT 令牌是攻击者不得访问的敏感信息(通过 XSS)
    • 从我的角度来看,访问令牌本身不会扩大攻击范围.如果攻击者可以控制受害者的浏览器,他们就可以使用令牌从受影响的浏览器本身执行调用.
    • 访问令牌通常具有相当短的到期时间,并且它们可以固定在浏览器中,从而减少在 XSS 上下文之外使用它们的机会.
  • Auth0 建议使用他们 SDK 中的 auth0.getTokenSilently() 来获取令牌,但据我所知,攻击者没有任何理由不能自己调用​​此方法(即注入另一个 sdk 脚本,使用现有的客户端密钥,并从那里调用 getToken),从而以与存储在 localStorage
  • 中几乎相同的方式获取令牌
  • 我知道 XSS 无法访问令牌的唯一方法基本上是使用 httpOnly cookie,但这本身会创建新的向量 (CSRF),并且仍然无法阻止攻击者从内部调用 api受影响的浏览器.

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

解决方案

虽然我对 Auth0 的实现、特性和设计决策不太了解,但从我对 OAuth2 和安全性的一般理解,我可以尝试连接点.


单个推荐本身并不能提供足够的安全性或所需的功能,但是当与其他相关推荐组合使用时,我们可以实现所需的安全性和行为级别.

让我们回顾一下你提出的观点.

<块引用>

从我的角度来看,访问令牌本身不会扩大攻击范围.如果攻击者可以控制受害者的浏览器,他们可以使用令牌从受影响的浏览器本身执行调用

localstorage 的问题是:

  1. localStoragesessionStorage 不跨子域共享.这是 SSO 功能的显示阻止器(有一些使用 iframe 的解决方案,但那些看起来更像是解决方法而不是一个好的解决方案.当响应头 X-Frame-Options 用于避免点击劫持攻击时使用 iframe,任何使用 iframe 的解决方案都是不可能的)

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

注意:第 2 点中提到的漏洞可以通过使用 Sender Constrained Access Tokens 方法,客户端必须证明他们确实拥有该令牌.另一种选择是指纹方法需要 cookie 的 OWASP.但是,似乎 Auth0 没有实现任何这些.因此,避免使用 localstorage 的建议是有道理的.

<块引用>

Auth0 建议使用他们 SDK 中的 auth0.getTokenSilently() 来获取令牌,但据我所知,攻击者没有任何理由不能自己调用​​此方法

正确.这就是为什么

  1. 我们需要通过遵循OWASP XSS 预防指南来降低 XSS 的风险第一名.
  2. 此外,getTokenSilently() 方法要求您在仪表板的 API 设置中启用允许跳过用户同意.虽然我没有看到关于此的具体指南,但我认为如果您将令牌存储在 cookie 中,则不需要启用此选项,从而消除了滥用该方法的任何可能性.

<块引用>

我知道 XSS 无法访问令牌的唯一方法基本上是使用 httpOnly cookie,但这本身会创建新的向量 (CSRF),并且仍然无法阻止攻击者从内部调用 api受影响的浏览器

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

  1. 使用 SameSite cookie.请参阅文档此处.如果浏览器不支持 SameSite cookie,请按照下面的另一种方法
  2. 状态变量(Auth0 使用它)- 客户端将生成并通过每个请求传递一个加密的强随机随机数,服务器将与其响应一起回显,允许客户端验证随机数.Auth0 doc 中对此进行了解释.
  3. 使用具有加密强随机值的 CSRF cookie,这样每个 AJAX 请求都会读取 cookie 值并将 cookie 值添加到自定义 HTTP 标头中(GET 和 HEAD 请求除外,它们不应该进行任何状态修改).由于CSRF由于同源策略无法读取任何内容,并且它基于利用POST,PUT和DELETE等不安全的HTTP方法,因此该CSRF cookie将减轻CSRF风险.所有现代 SPA 框架都使用这种使用 CSRF cookie 的方法.here
  4. 提到了 Angular 方法
  5. 始终检查referer 标头,仅当referer 是受信任域时才接受请求.如果引用标头不存在或域未列入白名单,只需拒绝请求即可.使用 SSL/TLS 时,通常会出现引用.登陆页面(主要是信息性的,不包含登录表单或任何受保护的内容可能有点放松,并允许缺少引用标头的请求
  6. 应该在服务器中阻止 TRACE HTTP 方法,因为这可用于读取 httpOnly cookie
  7. 另外,设置标题 Strict-Transport-Security: max-age=;includeSubDomains 只允许安全连接,以防止任何中间人覆盖来自子域的 CSRF cookie

Auth0 provide extensive list of resources describing best practices for the authentication. Among them there's a constant stream of advice not to use localStorage as a mean to store (JWT) tokens.

I've found several issues with those points:

  • There's strong assumption that JWT token is the sensitive information that mustn't be accesses by the attacker (via XSS)
    • 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.
    • Access tokens usually have fairly short expiration time and they can be browser-pinned, reducing the opportunity to use them outside of XSS context.
  • 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 (i.e. injecting another sdk script, using the existing client keys, and just calling the getToken from there), thus obtaining the token in pretty much the same manner as if it was stored in localStorage
  • 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.

So I fully agree with OWASP recommendation, not to store sensitive data in localStorage, I would never think of storing credit card numbers or passwords or even personal data there. But that's only because those things would allow attacker to expand the scope of their attack (access the bank account, try to reuse user's passwords in other apps, etc.). But I struggle to see how are accessTokens affected by this.

解决方案

Although I don't know much about Auth0 implementations, features and design decisions, from my general understanding of OAuth2 and security, I can try connecting the dots.


A single recommendation by itself doesn't provide enough security or desired functionality, but when used with a combination of other related recommendations, we can achieve the desired level of security and behavior.

Let's go through the points you raised.

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

The problem with localstorage is:

  1. localStorage and sessionStorage are not shared across sub-domains. This is show stopper for SSO functionality (There are some solutions using iframe, but those look more like workarounds rather than a good solution. And when the response header X-Frame-Options is used to avoid clickjacking attacks with iframe, any solution with iframe is out of question)

  2. XSS can send the access and/or refresh tokens to remote servers controlled by the attacker and thus allowing the attacker to impersonate the user

Note: The vulnerability mentioned in point 2 can be mitigated by using a Sender Constrained Access Tokens approach where the client has to prove that they indeed own the token. Another alternative is the fingerprint approach mentioned in OWASP which needs a cookie. However, it seems Auth0 doesn't implement any of these. Therefore, the recommendation of avoiding localstorage makes sense.

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

Correct. That's why

  1. we need to mitigate the risks of XSS by following OWASP XSS prevention guidelines in the first place.
  2. Also, the getTokenSilently() method requires you to have Allow Skipping User Consent enabled in your API Settings in the Dashboard. Although I don't see a specific guideline on this, but I think if you store the token in cookies you don't need this option to be enabled and thereby eliminating any possibility of misuse of the method.

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

True. But you can mitigate this with one or a combination of the following approaches:

  1. Use a SameSite cookie. Refer the doc here. If the browser doesn't support SameSite cookie, follow another approach from below
  2. State Variable (Auth0 uses it) - The client will generate and pass with every request a cryptographically strong random nonce which the server will echo back along with its response allowing the client to validate the nonce. It's explained in Auth0 doc.
  3. Use a CSRF cookie with a cryptographically strong random value such that every AJAX request reads the cookie value and add the cookie value in a custom HTTP header (except GET and HEAD requests which are not supposed to do any state modifications). Since CSRF cannot read anything due to same origin policy and it is based on exploiting the unsafe HTTP methods like POST, PUT and DELETE, this CSRF cookie will mitigate the CSRF risk. This approach of using CSRF cookie is used by all modern SPA frameworks. The Angular approach is mentioned here
  4. Always check the referer header and accept requests only when referer is a trusted domain. If referer header is absent or a non-whitelisted domain, simply reject the request. When using SSL/TLS referrer is usually present. Landing pages (that is mostly informational and not containing login form or any secured content may be little relaxed ​and allow requests with missing referer header
  5. TRACE HTTP method should be blocked in the server as this can be used to read the httpOnly cookie
  6. Also, set the header Strict-Transport-Security: max-age=<expire-time>; includeSubDomains​ to allow only secured connections to prevent any man-in-the-middle overwrite the CSRF cookies from a sub-domain

这篇关于为什么 auth0 建议不要在 localStorage 中存储令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆