问题描述
Auth0提供了大量资源列表,这些资源描述了认证的最佳实践.其中不断有建议不要使用localStorage
作为存储(JWT)令牌的手段.
- https://auth0 .com/docs/security/store-tokens#don-t-store-tokens-in-local-storage
- https://github.com/OWASP /CheatSheetSeries/blob/master/cheatsheets/HTML5_Security_Cheat_Sheet.md#local-storage
- https://github.com/auth0/docs/issues?utf8 =%E2%9C%93& q = localstorage
我发现这些问题有几个问题:
- 有一个很强的假设,即JWT令牌是攻击者(不能通过XSS)访问的敏感信息.
- 从我的角度来看,访问令牌本身并不会扩大攻击范围.如果攻击者控制了受害者的浏览器,则他们可以使用令牌从受影响的浏览器本身执行调用.
- 访问令牌通常具有相当短的到期时间,并且可以将它们固定在浏览器中,从而减少了在XSS上下文之外使用它们的机会.
- Auth0建议从其SDK中使用
auth0.getTokenSilently()
来获取令牌,但据我所知,不应有任何理由使攻击者无法自行调用此方法(即,使用现有的方法注入另一个sdk脚本)客户端密钥,然后从那里调用getToken),从而获得令牌的方式几乎与将其存储在localStorage
中的方式相同 - 我知道XSS无法访问令牌的唯一方法基本上是使用httpOnly cookie,但它本身会创建新的向量(CSRF),并且仍然不会阻止攻击者从内部调用api.受影响的浏览器.
因此,我完全同意OWASP的建议,不要将敏感数据存储在localStorage
中,我从不考虑在其中存储信用卡号或密码,甚至是个人数据.但这仅仅是因为这些事情会使攻击者扩大攻击范围(访问银行帐户,并尝试在其他应用中重用用户的密码,等等).但是我很难看到accessTokens对此有何影响.
尽管我对Auth0的实现,功能和设计决策了解不多,但从我对OAuth2和安全性的一般理解中,我可以尝试将各个问题联系起来. /p>
单条建议本身并不能提供足够的安全性或所需的功能,但是与其他相关建议结合使用时,我们可以达到所需的安全性和行为水平.
让我们逐一阐明您提出的观点.
localstorage
的问题是:
-
localStorage
和sessionStorage
不在子域之间共享.这是SSO功能的止挡器(有一些使用iframe
的解决方案,但这些解决方案看起来更像是变通方法,而不是一个好的解决方案.并且当使用响应标头X-Frame-Options来避免使用iframe
进行点击劫持攻击时,iframe
的任何解决方案都是毫无疑问的) -
XSS可以将访问和/或刷新令牌发送到攻击者控制的远程服务器,从而允许攻击者模拟用户
注意:通过使用发件人受限访问令牌方法,客户端必须证明他们确实拥有该令牌.另一种选择是指纹方法 OWASP,它需要一个cookie.但是,似乎Auth0并没有实现其中的任何一个.因此,避免使用localstorage
的建议是有道理的.
正确.这就是为什么
- 我们需要遵循以下内容中的 OWASP XSS预防指南,以减轻XSS的风险.第一名.
- 此外,
getTokenSilently()
方法要求您在仪表板的"API设置"中启用Allow Skipping User Consent
.尽管我对此没有特定的指导原则,但是我认为如果将令牌存储在cookie中,则不需要启用此选项,从而消除了滥用该方法的可能性.
是的.但是您可以使用以下一种或多种方法来缓解这种情况:
- 使用
SameSite
cookie.请在此处上参阅文档.如果浏览器不支持SameSite
cookie,请采用下面的另一种方法 - 状态变量(Auth0使用它)-客户端将生成并随每个请求传递一个加密强度高的随机随机数,服务器将随其响应一起回显该随机随机数,以允许客户端验证随机数.在 Auth0文档中进行了解释.
- 使用CSRF cookie并使用具有强密码强度的随机值,以便每个AJAX请求都读取cookie值并将cookie值添加到自定义HTTP标头中(不应该对状态进行任何修改的GET和HEAD请求除外).由于CSRF由于相同的原始策略而无法读取任何内容,并且基于利用不安全的HTTP方法(例如POST,PUT和DELETE),因此该CSRF cookie将减轻CSRF的风险.所有现代SPA框架都使用这种使用CSRF cookie的方法.在此处 中提到了Angular方法
- 始终检查引荐来源标头,并且仅在引荐来源为可信域时才接受请求.如果没有引荐来源标头或非列入白名单的域,则只需拒绝该请求即可.使用SSL/TLS时,通常会存在引荐来源网址.登陆页面(主要是信息性的,不包含登录表单或任何受保护的内容,可能会稍微放松一些,并允许缺少引荐标头的请求
- TRACE HTTP方法应在服务器中被阻止,因为该方法可用于读取httpOnly cookie
- 此外,将标题设置为
Strict-Transport-Security: max-age=<expire-time>; 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.
- https://auth0.com/docs/security/store-tokens#don-t-store-tokens-in-local-storage
- https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/HTML5_Security_Cheat_Sheet.md#local-storage
- https://github.com/auth0/docs/issues?utf8=%E2%9C%93&q=localstorage
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 inlocalStorage
- 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.
The problem with localstorage
is:
localStorage
andsessionStorage
are not shared across sub-domains. This is show stopper for SSO functionality (There are some solutions usingiframe
, 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 withiframe
, any solution withiframe
is out of question)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.
Correct. That's why
- we need to mitigate the risks of XSS by following OWASP XSS prevention guidelines in the first place.
- Also, the
getTokenSilently()
method requires you to haveAllow 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.
True. But you can mitigate this with one or a combination of the following approaches:
- Use a
SameSite
cookie. Refer the doc here. If the browser doesn't supportSameSite
cookie, follow another approach from below - 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.
- 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
- 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
- TRACE HTTP method should be blocked in the server as this can be used to read the httpOnly cookie
- 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中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!