我目前正在使用ReactJS构建一个单页应用程序。
我读到不使用localStorage的原因之一是因为XSS漏洞。
既然React会转义所有用户输入,那么现在使用localStorage是否安全呢?
我目前正在使用ReactJS构建一个单页应用程序。
我读到不使用localStorage的原因之一是因为XSS漏洞。
既然React会转义所有用户输入,那么现在使用localStorage是否安全呢?
当前回答
我知道这是一个老问题,但根据@mikejones1477所说,现代前端库和框架转义文本,为您提供对XSS的保护。cookie不是使用凭证的安全方法的原因是,当localStorage阻止CSRF时,cookie不能阻止CSRF(还要记住,cookie也可以通过JavaScript访问,所以XSS不是这里的大问题),这就是为什么的答案。
在本地存储中存储身份验证令牌并手动将其添加到每个请求中以防止CSRF的原因是关键字:手动。由于浏览器不会自动发送认证令牌,如果我访问邪恶。例如,它设法发送一个POST http://example.com/delete-my-account,它将无法发送我的authn令牌,因此该请求被忽略。
当然httpOnly是圣杯,但你不能从reactjs或任何js框架访问,你仍然有CSRF漏洞。我的建议是localstorage,或者如果你想使用cookie,确保像Django一样实现一些解决CSRF问题的解决方案。
关于CDN,确保你没有使用一些奇怪的CDN,例如谷歌或bootstrap提供的CDN,由社区维护,不包含恶意代码,如果你不确定,你可以自由审查。
其他回答
要记住的一件事是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)
在大多数现代单页应用程序中,我们确实必须将令牌存储在客户端某处(最常见的用例——在页面刷新后保持用户登录)。
总共有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。
只要加密,将令牌存储在localStorage中是安全的。下面是一个压缩的代码片段,展示了许多方法中的一种。
import SimpleCrypto from 'simple-crypto-js';
const saveToken = (token = '') => {
const encryptInit = new SimpleCrypto('PRIVATE_KEY_STORED_IN_ENV_FILE');
const encryptedToken = encryptInit.encrypt(token);
localStorage.setItem('token', encryptedToken);
}
然后,在使用令牌之前,使用PRIVATE_KEY_STORED_IN_ENV_FILE对其进行解密
TLDR;
两者都可以工作,但是使用httpOnly cookie要比使用localStorage安全得多,因为XSS引入的任何恶意javascript代码都可以读取localStorage。
看待这个问题的一种方法是考虑风险或伤害的水平。
你是否正在创造一款没有用户的应用,即POC/MVP?你是一家需要快速进入市场并测试应用程序的初创公司吗?如果是,我可能只会实施最简单的解决方案,并继续专注于寻找适合市场的产品。使用localStorage,因为它通常更容易实现。
你是在开发一款拥有大量日活跃用户的应用的v2版本,还是一款人们/企业非常依赖的应用?被黑客攻击是否意味着几乎没有恢复空间?如果是这样,我会仔细研究一下您的依赖关系,并考虑将令牌信息存储在仅http的cookie中。
使用localStorage和cookie/session存储都有各自的优缺点。
正如第一个答案所述:如果您的应用程序有XSS漏洞,那么两者都不能保护您的用户。由于大多数现代应用程序都有十几个或更多不同的依赖项,因此越来越难以保证应用程序的某个依赖项不受XSS攻击。
如果您的应用程序确实存在XSS漏洞,并且黑客已经能够利用它,那么黑客将能够代表您的用户执行操作。黑客可以通过从localStorage检索令牌来执行GET/POST请求,或者如果令牌存储在http-only cookie中,则可以执行POST请求。
在本地存储中存储令牌的唯一缺点是黑客将能够读取您的令牌。