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

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

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


当前回答

要记住的一件事是jwt是否:

第一方。简单地访问您自己的服务器命令) 第三方;谷歌,Facebook, Twitter等的JWT)

如果智威汤逊是第一方:

那么,将JWT存储在本地存储还是安全的cookie(例如。HttpOnly, SameSite=严格,安全)[假设你的网站已经在使用HTTPS,它应该]。

This is because, assuming an XSS attack succeeds (ie. an attacker was able to insert Javascript code through a JS dependency that is now running on all visitor browsers), it's "game over" anyway; all the commands which were meant to be secured by the "JWT token verifications", can now be executed by the attacker just by having the script they've inserted into the frontend JS call all the needed endpoints. Even though they can't read the JWT token itself (because of the cookie's http-only flag), it doesn't matter because they can just send all the needed commands, and the browser will happily send the JWT token along with those commands.

现在,虽然xss攻击的情况可以说是“游戏结束”了(无论是本地存储还是安全cookie),但cookie还是稍微好一点,因为攻击者只有在用户在浏览器中打开网站时才能执行攻击。

这会给攻击者带来以下“烦恼”:

"My XSS injection worked! Okay, time to collect private data on my boss and use it as blackmail. Dang it! He only ever logs in while I'm here at work. I'll have to prepare all my code ahead of time, and have it run within the three minutes he's on there, rather than getting to poke around into his data on the platform in a more gradual/exploratory way." "My XSS injection worked! Now I can change the code to send all Bitcoin transfers to me instead! I don't have any particular target in mind, so I don't need to wait for anyone. Man though, I wish I could access the JWT token itself -- that way I could silently collect them all, then empty everyone's wallets all at once. With these cookie-protected JWTs, I may only be able to hijack a few dozen visitors before the devs find out and suspend transfers..." "My XSS injection worked! This'll give me access to even the data that only the admins can see. Hmmm, unfortunately I have to do everything through the user's browser. I'm not sure there's a realistic way for me to download those 3gb files using this; I start the download, but there are memory issues, and the user always closes the site before it's done! Also, I'm concerned that client-side retransfers of this size might get detected by someone."

如果JWT是第三方:

在这种情况下,这实际上取决于第三方jwt允许持有者做什么。

如果他们所做的一切只是让某人“访问每个用户的基本配置文件信息”,那么如果攻击者能够访问它,那么它就不是那么糟糕;一些电子邮件可能会泄露,但攻击者可能会通过导航到用户的“帐户页面”,其中数据显示在UI中。(使用JWT令牌只是让他们避免了上一节中列出的“烦恼”)

相反,如果第三方jwt允许您做更实质性的事情——例如完全访问它们的云存储数据、在第三方平台上发送消息、在第三方平台上读取私有消息等等,那么访问jwt确实比仅仅能够“发送经过身份验证的命令”差得多。

这是因为,当攻击者无法访问实际的JWT时,他们必须通过您的第一方服务器路由所有命令。这样做有以下优点:

Limited commands: Because all the commands are going through your server, attackers can only execute the subset of commands that your server was built to handle. For example, if your server only ever reads/writes from a specific folder in a user's cloud storage, then the attacker has the same limitation. Easier detection: Because all the commands are going through your server, you may be able to notice (through logs, sudden uptick in commands, etc.) that someone has developed an XSS attack. This lets you potentially patch it more quickly. (if they had the JWTs themselves, they could silently be making calls to the 3rd-party platforms, without having to contact your servers at all) More ways to identify the attacker: Because the commands are going through your server, you know exactly when the commands are being made, and what ip-address is being used to make them. In some cases, this could help you identify who is doing the attacks. The ip-address is the most obvious way, though admittedly most attackers capable of XSS attacks would be aware enough to use a proxy. A more advanced identification approach might be to, say, have a special message pop up that is unique for each user (or, at least, split into buckets), of such a nature that the attacker (when he loads up the website from his own account) will see that message, and try to run a new command based on it. For example, you could link to a "fake developer blog post" talking about some "new API" you're introducing, which allows users to access even more of their private data; the sneaky part is that the URL for that "new API" is different per user viewing the blog post, such that when the API is attempted to be used (against the victim), you know exactly who did it. Of course, this relies on the idea that the attacker has a "real account" on the site alongside the victim, and could be tempted/fooled by this sort of approach (eg. it won't work if the attacker knows you're onto him), but it's an example of things you can do when you can intercept all authenticated commands. More flexible controlling: Lets say that you've just discovered that someone deployed an XSS attack on your site. If the attackers have the 3rd-party JWTs themselves, your options are limited: you have to globally disable/reset your OAuth/JWT configuration for all 3rd-party platforms. This causes serious disruption while you try to figure out the source of the XSS attack, as no one is able to access anything from those 3rd-party platforms. (including your own server, since the JWT tokens it may have stored are now invalid) If the JWT tokens are instead protected in http-only cookies, you have more options: You can simply modify your server to "filter out" any reads/writes that are potentially dangerous. In some cases added this "filtering" is a quick and easy process, allowing your site to continue in "read-only"/"limited" mode without disrupting everything; in other cases, things may be complex enough that it's not worth trusting the filter code for security. The point though is that you have more options. For example, maybe you don't know for sure that someone has deployed an XSS attack, but you suspect it. In this case, you may not want to invalidate the JWT tokens of every user (including those your server is using in the background) simply on the suspicion of an XSS attack (it depends on your suspicion level). Instead, you can just "make things read-only for a while" while you look into the issue more closely. If it turns out nothing is wrong, you can just flip a switch and re-enable writes, without everyone having to log back in and such.

无论如何,由于这四个好处,我决定始终将第三方jwt存储在“安全cookie”中,而不是本地存储中。虽然目前第三方jwt的作用域非常有限(因此如果它们被窃取也不是什么大问题),但这样做是很好的未来证明,以防我希望我的应用程序在未来请求访问更多特权功能(例如。访问用户的云存储)。

Note: The four benefits above (for storing third-party JWTs in secured cookies) may also partially apply for first-party JWTs, if the JWTs are used as authentication by multiple backend services, and the domains/ip-addresses of these other servers/services are public knowledge. In this case, they are "equivalent to third-party platforms", in the sense that "http-only cookies" restrict the XSS attacker from sending direct commands to those other servers, bringing part of the benefits of the four points above. (it's not exactly the same, since you do at least control those other servers, so you can activate read-only mode for them and such -- but it'll still generally be more work than making those changes in just one place)

其他回答

基本上可以将JWT存储在localStorage中。

我认为这是一个好方法。 如果我们谈论的是XSS, XSS使用CDN,这也是一个潜在的风险,获得您客户的登录/通行证。将数据存储在本地至少可以防止CSRF攻击。

你需要了解这两点,然后选择你想要的。这两种攻击都不是你所需要注意的,只要记住:你的整个应用程序的安全性仅与你的应用程序的最不安全的点一样。

再次重申,存储是OK的,易受XSS, CSRF,…不是

TLDR;

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

localStorage和httpOnly cookie都不能接受吗?关于一个妥协的第三方库,我所知道的唯一能减少/防止敏感信息被窃取的解决方案是强制执行子资源完整性。

子资源完整性(SRI)是一种安全特性 浏览器验证它们获取的资源(例如从CDN) 交付时没有意外的操作。它通过允许 您可以提供所获取资源必须的加密散列 匹配。

只要受感染的第三方库在您的网站上是活跃的,键盘记录程序就可以开始收集信息,如用户名,密码,以及您输入到网站的任何其他内容。

httpOnly cookie将阻止来自另一台计算机的访问,但不会阻止黑客操纵用户的计算机。

如果你使用CDN是不安全的:

恶意JavaScript可以嵌入到页面中,Web存储就会受到威胁。这些类型的XSS攻击可以在不知情的情况下获取访问您站点的每个人的Web存储。这可能就是为什么许多组织建议不要在网络存储中存储任何有价值的东西或信任任何信息的原因。这包括会话标识符和令牌。 通过stormpath

您从外部需要的任何脚本都可能被破坏,并可能从客户机的存储中获取任何JWTS,并将个人数据发送回攻击者的服务器。

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

总共有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。