我目前正在使用ReactJS构建一个单页应用程序。

我读到不使用localStorage的原因之一是因为XSS漏洞。

既然React会转义所有用户输入,那么现在使用localStorage是否安全呢?


当前回答

我加入讨论的时间比较晚,但是由于OpenID Connect等更成熟和现代的认证协议的优势。

TL;DR:首选的方法是将JWT Token存储在内存中:而不是在cookie中,也不是在本地存储中。

细节

您希望将用户身份验证的责任与应用程序的其他工作分离开来。Auth很难得到正确的答案,少数几个花了所有时间思考这个问题的团队可能会担心你我永远都不会得到正确答案的细节。

为你的应用建立一个专用的身份提供者,并使用OpenID Connect协议进行身份验证。这可能是像谷歌、Microsoft或Okta这样的提供商,也可能是与一个或多个其他服务联合的轻量级身份服务器。

使用授权码流让用户验证并获得应用程序的访问令牌。使用一个受尊重的客户端库来处理OpenID连接细节,这样你就可以让库在应用程序拥有有效令牌、通过刷新获得新的有效令牌或当令牌无法刷新(因此用户需要再次验证)时通知应用程序。应该对库进行配置(可能是默认情况),以避免存储令牌。

FAQ

当有人刷新页面时会发生什么?我不想让他们再次登录。

When the app first loads, it should always redirect the user to your Identity Provider. Based on how that identity provider handles things, there's a good chance the user won't have to log in. For example, if you're federating to an identity provider like Google or Microsoft, the user may have selected an option indicating that they are on a trusted device and they want to be remembered. If so, they won't need to log in again for a very long time, long after your auth token would have expired. This is much more convenient for your users.

同样,如果用户表示他们在共享设备上,将来不应该自动登录,那么您希望强制再次登录:您无法区分刷新浏览器窗口的用户和重新打开关闭的浏览器并导航到存储在浏览器历史记录中的页面的用户。

身份提供者不是使用cookie来保持用户登录吗?那么CSRF或XSS攻击呢?

这些实现细节是特定于身份提供程序的。如果他们使用cookie,他们的工作就是实施反csrf措施。他们比你更不可能使用有问题的第三方库,或者导入有问题的外部组件,因为他们的应用程序只有一个任务。

难道我不应该花时间解决XSS攻击吗?如果有人向我的应用程序中注入代码,这难道不是“游戏结束”吗?

如果这是一个非此即彼的命题,并且你有理由相信你的应用程序存在XSS或代码注入漏洞,那么这些肯定应该优先考虑。但是,对于一种分层的安全性来说,良好的安全性包括在多个级别上遵循最佳实践。

此外,使用受信任的第三方库连接到受信任的第三方安全提供者应该有望节省您处理各种其他安全相关问题的时间。

其他回答

看待这个问题的一种方法是考虑风险或伤害的水平。

你是否正在创造一款没有用户的应用,即POC/MVP?你是一家需要快速进入市场并测试应用程序的初创公司吗?如果是,我可能只会实施最简单的解决方案,并继续专注于寻找适合市场的产品。使用localStorage,因为它通常更容易实现。

你是在开发一款拥有大量日活跃用户的应用的v2版本,还是一款人们/企业非常依赖的应用?被黑客攻击是否意味着几乎没有恢复空间?如果是这样,我会仔细研究一下您的依赖关系,并考虑将令牌信息存储在仅http的cookie中。

使用localStorage和cookie/session存储都有各自的优缺点。

正如第一个答案所述:如果您的应用程序有XSS漏洞,那么两者都不能保护您的用户。由于大多数现代应用程序都有十几个或更多不同的依赖项,因此越来越难以保证应用程序的某个依赖项不受XSS攻击。

如果您的应用程序确实存在XSS漏洞,并且黑客已经能够利用它,那么黑客将能够代表您的用户执行操作。黑客可以通过从localStorage检索令牌来执行GET/POST请求,或者如果令牌存储在http-only cookie中,则可以执行POST请求。

在本地存储中存储令牌的唯一缺点是黑客将能够读取您的令牌。

TLDR;

两者都可以工作,但是使用httpOnly cookie要比使用localStorage安全得多,因为XSS引入的任何恶意javascript代码都可以读取localStorage。

Philippe De Ryck博士写了一篇有用的文章,深入分析了漏洞(尤其是XSS)的真正影响。

这篇文章让人大开眼界!

简而言之,开发人员最关心的应该是保护web应用程序不受XSS的影响,而不应该太担心使用哪种类型的存储区域。

菲利普医生建议采取以下3个步骤:

Don't worry too much about the storage area. Saving an access token in localStorage area will save the developer a massive amount of time for development of next phases of the application. Review your app for XSS vulnerabilities. Perform a through code review and learn how to avoid XSS within the scope of your templating framework. Build a defense-in-depth mechanism against XSS. Learn how you could further lock down your application. E.g. utilising Content Security Policy (CSP) and HTML5 sandboxing.

记住,一旦你被XSS攻击了,游戏就结束了!

我对所有建议不要存储在本地存储的答案感到不安,因为这很容易受到XSS攻击或恶意库的攻击。其中一些问题甚至会进入冗长的讨论,尽管答案非常小/简单,我很快就会讲到。

这就相当于说:“不要用煎锅做饭,因为如果你某天晚上喝醉了,决定用煎锅做饭,你会把自己和房子都烤焦的。” 如果jwt由于XSS攻击或恶意库而泄露,那么站点所有者就有更大的问题:他们的站点容易受到XSS攻击或正在使用恶意库。

答案是:如果你确信你的网站不存在这些漏洞,那就去做吧。

裁判:https://auth0.com/docs/security/data-security/token-storage # browser-local-storage-scenarios

在大多数现代单页应用程序中,我们确实必须将令牌存储在客户端某处(最常见的用例——在页面刷新后保持用户登录)。

总共有2个选项可用:Web Storage(会话存储,本地存储)和客户端cookie。这两种方法都被广泛使用,但这并不意味着它们非常安全。

Tom Abbott很好地总结了JWT sessionStorage和localStorage安全性:

Web Storage (localStorage/sessionStorage) is accessible through JavaScript on the same domain. This means that any JavaScript running on your site will have access to web storage, and because of this can be vulnerable to cross-site scripting (XSS) attacks. XSS, in a nutshell, is a type of vulnerability where an attacker can inject JavaScript that will run on your page. Basic XSS attacks attempt to inject JavaScript through form inputs, where the attacker puts <script>alert('You are Hacked');</script> into a form to see if it is run by the browser and can be viewed by other users.

为了防止XSS,常见的响应是转义和编码所有不可信的数据。React(主要)为您做这些!这里有一个关于React在多大程度上负责XSS漏洞保护的很好的讨论。

但这并没有涵盖所有可能的漏洞!另一个潜在威胁是JavaScript托管在cdn或外部基础设施上的使用。

汤姆说:

Modern web apps include 3rd party JavaScript libraries for A/B testing, funnel/market analysis, and ads. We use package managers like Bower to import other peoples’ code into our apps. What if only one of the scripts you use is compromised? Malicious JavaScript can be embedded on the page, and Web Storage is compromised. These types of XSS attacks can get everyone’s Web Storage that visits your site, without their knowledge. This is probably why a bunch of organizations advise not to store anything of value or trust any information in web storage. This includes session identifiers and tokens.

因此,我的结论是,作为一种存储机制,Web storage在传输过程中没有强制执行任何安全标准。任何阅读Web Storage并使用它的人都必须尽职尽责,以确保始终通过HTTPS而不是HTTP发送JWT。