我目前正在使用reactjs构建单页面应用程序。我读到很多不使用localStorage的原因是因为XSS漏洞。由于React逃脱了所有用户输入,现在使用localStorage是否安全?
答案 0 :(得分:92)
在大多数现代单页面应用程序中,我们确实必须将令牌存储在客户端的某个位置(最常见的用例 - 在页面刷新后让用户保持登录状态)。
共有2个选项:Web存储(会话存储,本地存储)和客户端cookie。 这两个选项都被广泛使用,但这并不意味着它们非常安全。
Tom Abbott很好地总结了JWT sessionStorage and localStorage security:
可以通过同一域上的JavaScript访问Web存储(localStorage / sessionStorage)。这意味着您网站上运行的任何JavaScript都可以访问网络存储,因此可能容易受到跨网站脚本攻击(XSS)攻击。简而言之,XSS是一种漏洞,攻击者可以在其中注入将在您的页面上运行的JavaScript。基本的XSS攻击试图通过表单输入注入JavaScript,攻击者将
<script>alert('You are Hacked');</script>
放入表单中,以查看它是否由浏览器运行,并且可以被其他用户查看。
为防止XSS,常见的响应是转义并编码所有不受信任的数据。 React(大多数)为你做这件事!这是一个很棒的discussion about how much XSS vulnerability protection is React responsible for。
但这并不能涵盖所有可能的漏洞!另一个潜在的威胁是使用托管在CDN或外部基础设施上的JavaScript 。
再次来到汤姆:
现代网络应用包括用于A / B测试,渠道/市场分析和广告的第三方JavaScript库。我们使用像Bower这样的包管理器将其他人的代码导入我们的应用程序。
如果您使用的其中一个脚本遭到入侵,该怎么办?恶意JavaScript可以嵌入到页面中,并且Web存储会受到损害。 这些类型的XSS攻击可以让每个人的Web存储在他们不知情的情况下访问您的网站。这可能是为什么一群组织建议不要存储任何有价值的东西或信任Web存储中的任何信息。这包括会话标识符和令牌。
因此,我的结论是,作为一种存储机制,Web存储在传输过程中不会强制执行任何安全标准。读取Web存储并使用它的人必须尽职尽责,以确保他们始终通过HTTPS发送JWT,而不是HTTP。
答案 1 :(得分:19)
我知道这是一个老问题,但根据@ mikejones1477的说法,现代前端库和框架逃脱了文本,为您提供了对XSS的保护。 Cookie不是使用凭据的安全方法的原因是,当localStorage执行时,cookie不会阻止CSRF(还记得javascript也可以访问cookie,因此XSS不是这里的大问题),this answer resume why。
将身份验证令牌存储在本地存储中并手动将其添加到每个请求的原因可以防止CSRF成为关键字:manual。由于浏览器没有自动发送该身份验证令牌,如果我访问evil.com并且它设法发送POST http://example.com/delete-my-account,它将无法发送我的authn令牌,因此请求被忽略。
当然,httpOnly是圣杯,但你不能从reactjs或任何js框架访问你仍然有CSRF漏洞。我的建议是localstorage,或者如果你想使用cookies,请确保为CSRF problem like django does实施一些解决方案。
关于CDN,请确保您没有使用某些奇怪的CDN,例如像google或bootstrap提供的CDN,由社区维护并且不包含恶意代码,如果您不确定,那么您是免费的审查。
答案 2 :(得分:5)
如果您使用CDN,则不安全:
恶意JavaScript可以嵌入到页面中,并且Web存储会受到影响。这些类型的XSS攻击可以让每个人在不知情的情况下访问您的网站。这可能是为什么一群组织建议不要存储任何有价值的东西或信任网络存储中的任何信息。这包括会话标识符和令牌。
您从外部需要的任何脚本都可能受到攻击,并且可以从客户端的存储中获取任何JWTS并将个人数据发送回攻击者的服务器。
答案 3 :(得分:3)
基本上可以将JWT存储在localStorage中。
我认为这是好方法。 如果我们谈论XSS,XSS使用CDN,它也有潜在的风险,让您的客户端登录/通过。将数据存储在本地存储中至少可以防止CSRF攻击。
您需要了解两者并选择您想要的。这两种攻击都不是你需要注意的,只要记住:你确保你的应用程序的安全性较低。
再次存储是可以的,容易受到XSS,CSRF的攻击,......不是
答案 4 :(得分:2)
一种解决方法是考虑风险或损害的程度。
您是否正在构建没有用户的应用程序,POC / MVP?您是一家需要迅速进入市场并测试您的应用程序的初创公司吗?如果是的话,我可能只会实施最简单的解决方案,并专注于找到适合市场的产品。使用localStorage常常易于实现。
您是在构建具有许多日常活动用户的应用程序还是人们/企业严重依赖的应用程序的v2。被黑客入侵意味着恢复的空间很小或没有?如果是这样,我将认真研究您的依赖关系,并考虑将令牌信息存储在仅HTTP cookie中。
同时使用localStorage和cookie / session存储各有利弊。
如第一个答案所述:如果您的应用程序具有XSS漏洞,则两者都无法保护您的用户。由于大多数现代应用程序具有十几个或更多不同的依赖关系,因此越来越难以保证应用程序的一个依赖关系不受XSS攻击。
如果您的应用程序确实存在XSS漏洞,并且黑客能够利用它,则该黑客将能够代表您的用户执行操作。黑客可以通过从localStorage检索令牌来执行GET / POST请求,或者如果令牌存储在仅HTTP的cookie中,则可以执行POST请求。
将令牌存储在本地存储中的唯一缺点是,黑客将能够读取您的令牌。
答案 5 :(得分:1)
Localstorage旨在通过javascript访问,因此它不提供任何XSS保护。正如其他答案中所提到的,有许多可能的方法来进行XSS攻击,默认情况下localstorage不受保护。
但是,cookie具有安全标志,可以防止XSS和CSRF攻击。 HttpOnly标志阻止客户端javascript访问cookie,安全标志仅允许浏览器通过ssl传输cookie,而SameSite标志确保cookie仅发送到源。虽然我刚刚检查过并且SameSite目前仅在Opera和Chrome中受支持,但为了防止CSRF,最好使用其他策略。例如,在具有一些公共用户数据的另一个cookie中发送加密令牌。
因此,cookie是存储身份验证数据的更安全选择。
答案 6 :(得分:0)
localStorage或httpOnly cookie都不可接受吗?对于受威胁的第三方库,我所知道的唯一可以减少/防止敏感信息被盗的解决方案将强制执行Subresource Integrity。
子资源完整性(SRI)是一项安全功能,可启用 浏览器以验证其获取的资源(例如,从CDN) 交付时没有意外的操作。通过允许 您提供获取的资源必须提供的加密哈希 匹配。
只要受感染的第三方库在您的网站上处于活动状态,键盘记录程序就可以开始收集用户名,密码以及您在网站中输入的任何其他信息。
httpOnly cookie将阻止从另一台计算机进行访问,但不会阻止黑客操纵用户的计算机。
答案 7 :(得分:0)
要记住的一件事是 JWT 是否:
如果 JWT 是第一方:
那么,将 JWT 存储在本地存储中还是安全 cookie(即 HttpOnly
、SameSite=strict
和 {{1 }}) [假设您的网站已经在使用 HTTPS,它应该如此]。
这是因为,假设 XSS 攻击成功(即攻击者能够通过现在在所有访问者浏览器上运行的 JS 依赖项插入 Javascript 代码),无论如何“游戏结束”;所有本应由“JWT 令牌验证”保护的命令现在都可以由攻击者执行,只需让他们插入前端 JS 的脚本调用所有需要的端点即可。即使他们无法读取 JWT 令牌本身(因为 cookie 的 http-only 标志),也没关系,因为他们可以发送所有需要的命令,浏览器会很高兴地将 JWT 令牌与这些命令一起发送.
现在,尽管 XSS 攻击情况可以说是“游戏结束”(无论是本地存储还是安全 cookie),cookie 仍然稍微更好,因为攻击者只能执行如果/当用户在浏览器中打开网站时的攻击。</p>
这会给攻击者带来以下“烦恼”:
如果 JWT 是第三方:
在这种情况下,这实际上取决于第三方 JWT 允许持有者做什么。
如果他们所做的只是让某人“访问每个用户的基本个人资料信息”,那么攻击者可以访问它并没有那么糟糕;一些电子邮件可能会泄漏,但攻击者可能无论如何都可以通过导航到用户的“帐户页面”来获取这些数据,该页面在 UI 中显示了该数据。 (拥有 JWT 令牌只是让他们避免上一节中列出的“烦恼”)
相反,如果第三方 JWT 让您做更多实质性的事情——例如完全访问他们的云存储数据,在第三方平台上发送消息,在第三方平台上阅读私人消息,等等,那么访问 JWT 确实比仅仅能够“发送经过身份验证的命令”要糟糕得多。
这是因为,当攻击者无法访问实际的 JWT 时,他们必须通过您的第一方服务器路由所有命令。这具有以下优点:
有限的命令:由于所有命令都通过您的服务器,因此攻击者只能执行您的服务器旨在处理的命令子集。例如,如果您的服务器只读取/写入用户云存储中的特定文件夹,那么攻击者也有同样的限制。
更容易检测:由于所有命令都通过您的服务器,您可能会注意到(通过日志、命令的突然增加等)有人开发了 XSS攻击。这使您可以更快地修补它。 (如果他们自己有 JWT,他们就可以默默地调用 3rd 方平台,而根本无需联系您的服务器)
识别攻击者的更多方法:因为命令通过您的服务器,所以您可以确切地知道命令是在什么时候发出的,以及使用什么 IP 地址来发出命令.在某些情况下,这可以帮助您确定谁在进行攻击。 ip-address 是最明显的方式,尽管不可否认,大多数能够进行 XSS 攻击的攻击者都会意识到使用代理。
一种更高级的识别方法可能是,例如,弹出一个对每个用户都是唯一的特殊消息(或者,至少,分成多个桶),其性质使得攻击者(当他加载网站从他自己的帐户)将看到该消息,并尝试基于它运行一个新命令。例如,您可以链接到“假开发者博客文章”,谈论您正在引入的一些“新 API”,它允许用户访问更多的私人数据;狡猾的部分是该“新 API”的 URL 每个查看博客文章的用户都不同,因此当尝试使用该 API 时(针对受害者),您确切地知道是谁做了它。当然,这依赖于攻击者在受害者旁边的站点上有一个“真实帐户”的想法,并且可能会被这种方法诱惑/愚弄(例如,如果攻击者知道你是到他身上),但这是当您可以拦截所有经过身份验证的命令时可以执行的操作的示例。
更灵活的控制:假设您刚刚发现有人在您的网站上部署了 XSS 攻击。
如果攻击者自己拥有 3rd 方 JWT,您的选择就很有限:您必须全局禁用/重置所有 3rd 方平台的 OAuth/JWT 配置。当您试图找出 XSS 攻击的来源时,这会导致严重的中断,因为没有人能够从那些 3rd 方平台访问任何东西。 (包括您自己的服务器,因为它可能存储的 JWT 令牌现在无效)
如果 JWT 令牌在 http-only cookie 中受到保护,您有更多选择:您可以简单地修改您的服务器以“过滤”任何有潜在危险的读/写。在某些情况下,添加此“过滤”是一个快速而简单的过程,允许您的站点在“只读”/“受限”模式下继续运行而不会中断一切;在其他情况下,事情可能足够复杂,以至于不值得相信过滤器代码的安全性。关键是你有更多的选择。
例如,您可能不确定知道有人部署了 XSS 攻击,但您对此表示怀疑。在这种情况下,您可能不想仅仅因为怀疑 XSS 攻击(这取决于您的怀疑级别)而使每个用户(包括您的服务器在后台使用的那些)的 JWT 令牌无效。相反,您可以在更仔细地研究问题时“暂时将内容设为只读”。如果结果没有问题,您只需拨动开关并重新启用写入,而无需每个人都重新登录等。
无论如何,由于这四个好处,我决定始终将第三方 JWT 存储在“安全 cookie”而不是本地存储中。虽然目前第三方 JWT 的范围非常有限(如果它们被盗了也没什么大不了的),但如果我希望我的应用程序请求访问更多特权功能,这样做是很好的面向未来将来(例如访问用户的云存储)。
注意:上述四个好处(用于将第三方 JWT 存储在安全 cookie 中)也可以部分适用第一方 JWT,如果 JWT 被多个后端服务用作身份验证,并且这些其他服务器/服务的域/IP 地址是公共知识。在这种情况下,它们“等同于第三方平台”,从某种意义上说,“http-only cookie”限制了 XSS 攻击者向其他服务器发送直接命令,从而带来部分好处以上四点。 (这并不完全相同,因为您至少可以控制那些其他服务器,因此您可以为它们激活只读模式等等——但它通常仍然比仅在一个地方进行这些更改要多得多)< /p>
答案 8 :(得分:-1)
将令牌加密就可以安全地将其存储在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
答案 9 :(得分:-1)
该问题的大多数答案(包括已接受的问题)都在谈论使用传统cookie,而localStorage被声明为存储敏感数据的不安全方式。但这不是事实。 localStorage与传统cookie一样安全。 JavaScript也可以访问cookie,那么如何说cookie是安全的而localStorage不是呢?
如果要允许来自用户的不受信任的数据,并且让一些JavaScript在您的网站上执行,那么最终将使攻击者可以使用访问权限,而与存储身份验证信息所用的媒体无关。 JavaScript可以劫持会话Cookie,或者可以允许您访问localStorage数据。
此外,在其他答案中还讨论了CSRF,但这与此处完全无关。 CSRF保护具有不同(但无用)的目的。如果您打算在代码中建立针对XSS的可靠保护,那么最好将localStorage用作身份验证凭据的安全之地。
This document详细讨论了会话劫持的可能性,并且主要针对cookie。
因此,最重要的是,如果允许黑客代表您执行JavaScript,那么无论是localStorage还是cookie,这两种方法都不安全。将localStorage视为一个储物柜。如果丢失了它的密钥,就不能指望它是安全的。您可以考虑其他答案中讨论的技巧,即不要使用不受信任的CDN中的JS来保护用户。