使用reactjs将jwt存储在localStorage中是否安全?


147

我目前正在使用reactjs构建一个单页面应用程序。我读到许多不使用localStorage的原因是由于XSS漏洞。由于React避开了所有用户输入,现在使用localStorage是否安全?


4
更喜欢会话存储
Praneet Rohida


3
“建议不要在本地存储中存储任何敏感信息。” -OWASP“将它们存储在内存中,而没有任何持久性” -Auth0
avejidah

我认为Auth0可能已经改变了他们的观点-因为在提供的链接中找不到上述报价
DauleDK

Answers:


141

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

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

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

Web存储(localStorage / sessionStorage)可通过同一域上的JavaScript访问。这意味着您网站上运行的所有JavaScript都可以访问Web存储,因此,它很容易受到跨站点脚本(XSS)攻击的攻击。简而言之,XSS是攻击者可以注入将在您的页面上运行的JavaScript的一种漏洞。基本的XSS攻击试图通过表单输入注入JavaScript,攻击者将JavaScript <script>alert('You are Hacked');</script>放入表单中,以查看它是否由浏览器运行并且可以被其他用户查看。

为了防止XSS,常见的响应是对所有不受信任的数据进行转义和编码。React(主要是)为您做到了!这是关于React负责多少XSS漏洞保护的精彩讨论

但这并不涵盖所有可能的漏洞!另一个潜在的威胁是托管在CDN或外部基础结构上的JavaScript的使用

再次是汤姆:

现代网络应用程序包括用于A / B测试,渠道/市场分析和广告的第三方JavaScript库。我们使用Bower等软件包管理器将其他人的代码导入我们的应用程序。

如果只破坏了您使用的一个脚本怎么办?恶意JavaScript可以嵌入到页面中,并且Web存储受到损害。这些类型的XSS攻击可能会导致所有人在不知情的情况下访问您站点的Web存储。这可能就是为什么许多组织建议不要在Web存储中存储任何有价值的东西或信任任何信息的原因。这包括会话标识符和令牌。

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


10
因此,如果我对您的理解正确,那么建议您使用Cookie?只想确认一下。谢谢!
SuperLemon

7
是。我建议使用cookie,因为它们提供了额外的安全性,以及使用现代Web框架防止CSRF的简单性。Web存储(localStorage / sessionStorage)易受XSS攻击,具有较大的攻击面,并且可以在成功攻击后影响所有应用程序用户。
Kaloyan Kosev

48
我想你把这些混在一起了吗?现代Web框架具有强大的XSS内置防御功能。但是对于xsrf来说却没有那么多。xsrf的最佳防御方法是避免完全使用cookie。本地存储被沙箱化到特定域,这意味着攻击者域无法访问它。Web框架通过自动编码和清除用户输入来抵御xss。参见angular.io/guide/security
mikejones1477 '17

47
如果“建议您使用[而不是] Cookies”,那么,我是否可以建议您在答案中的某处说出来?不仅仅是在评论中?
壮观的

7
我来晚了,现在才读这些主题,我对一件事感到困惑,如果您对Xss感到困惑,那么很多人都说您受到了仅HTTP cookie的保护,但是,如果您使用Xss该atacker不需要窃取您任何东西,他可以在页面上简单地发布一个帖子,以使用该cookie来冒充您(即使他不能窃取它)。我想念什么吗???
Borja Alvarez,

35

我知道这是一个老问题,但是根据@ mikejones1477所说的,现代的前端库和框架转义了文本,从而为您提供了针对XSS的保护。Cookies并非使用凭据的安全方法的原因是,当localStorage允许使用cookie时,cookie不会阻止CSRF(还请注意,cookie也可以通过javascript访问,因此XSS并不是这里的大问题),此答案恢复了为什么

关键字:手动是将身份验证令牌存储在本地存储中并手动将其添加到每个请求中的原因,可以防止CSRF。由于浏览器不会自动发送该身份验证令牌,因此,如果我访问evil.com并且它能够发送POST http://example.com/delete-my-account,它将无法发送我的身份验证令牌,因此该请求将被忽略。

当然,httpOnly是圣杯,但是您仍然无法通过CSRF漏洞访问reactjs或任何js框架。我的建议是使用本地存储,或者如果您要使用Cookie,请确保像django一样实现对CSRF问题的解决方案。

关于CDN,请确保您未使用某些怪异的CDN,例如,由google维护的CDN或Bootstrap提供的CDN由社区维护,并且不包含恶意代码;如果不确定,您可以自由进行审查。


2
不知道为什么您会说使用Cookie时仍然容易受到CSRF攻击。使用带有标志HttpOnly SameSite=strict和的cookie secure,将使您在cookie中设置的信息保持安全。然后针对XSS,只需确保您的JavaScript不知道任何与身份验证相关的数据,例如令牌和密码(即不要将它们存储在Web存储中)-如果导入恶意脚本,则该脚本将无权访问对敏感数据。是的,您也无法通过JS访问令牌,但这确实不是问题。
miphe

@miphe我就是这么说的。但是OP要求一种从javascript访问的方法。在这里,我只是在解释什么是存储可从js访问的令牌的最佳方法。
Mauricio Cortazar

21

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

我认为这是个好方法。如果我们谈论的是XSS,使用CDN的XSS,那么也存在潜在的风险,也可能会导致客户登录/通过。将数据存储在本地存储中至少可以防止CSRF攻击。

您需要了解两者并选择所需的内容。两种攻击都不是您需要了解的全部,只需记住:您的整个应用程序的安全性仅与您应用程序的最低安全点相同。

再一次存储就可以了,容易受到XSS,CSRF等的威胁。


2
这就是为什么它是安全的做到以下几点: -存储在这样它不能从XSS检索一个cookie的智威汤逊-储存在localStorage的令牌,因此它不能从CSRF被检索的CSRF
亚历杭德罗·卡瓦佐斯

33
您提出了一个很好的观点:如果您的站点运行了恶意脚本,那么无论如何它都是游戏。他们可以将keydown事件绑定到类型为password的输入,并以这种方式窃取用户的身份验证信息(这比窃取JWT auth令牌要糟糕得多)。在本地存储中存储JWT并不会增加XSS已经造成的巨大破坏。
卡尔·莱斯

8

如果使用CDN,则不安全:

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

通过暴风雨

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


6
如果我不打算使用CDN,那会安全吗?

1
本文的作者从未对通过CDN或直接从中央服务器提供服务的站点上的XSS进行区分。您的解释是否也将不仅适用于CDN,还普遍适用?
弗拉德(Vlad)'18

5

本地存储被设计为可通过javascript访问,因此它不提供任何XSS保护。如在其他答案中提到的那样,有很多方法可以进行XSS攻击,默认情况下,本地存储不受此方法的保护。

但是,Cookie具有安全标记,可以防止XSS和CSRF攻击。HttpOnly标志可防止客户端javascript访问cookie; Secure标志仅允许浏览器通过ssl传输cookie; SameSite标志可确保将cookie仅发送到源。尽管我刚刚检查过,Opera和Chrome当前仅支持SameSite,但是为了避免受到CSRF的影响,最好使用其他策略。例如,在另一个包含某些公共用户数据的cookie中发送加密令牌。

因此,cookie是用于存储身份验证数据的更安全的选择。


无法获得:HttpOnly如何保护您免受CSRF的侵害?
Alex Lyalka '17

@AlexLyalka并不是说HttpOnly可以防止CSRF,而不是所有cookie标志一起可以防止XSS和CSRF。SameSite提供了一些保护,防止cookie被发送到与原始站点不同的站点。尽管我刚刚检查了该标志的支持率很低。也可以避免使用带有某些用户标识的单独加密令牌的CSRF,该令牌在服务器上进行了检查。
伊万(Ivan)

1
好吧,如果有人可以在您的网站上执行代码,他能不能仅以您的用户名向您的网站发布信息?好的,他无法获取仅HTTP的cookie,但是他可以使用这些cookie进行呼叫,所以我仍然看不到重点
Borja Alvarez

2
@BorjaAlverez有很大的不同。是的,有人可以通过XSS代表已登录的用户发出请求,但破坏令牌的情况更糟。例如:令牌可以提供对客户端应用程序不使用的API的访问;令牌可能包含有关用户的其他信息(电子邮件地址,个人资料和授权);该令牌可用于对您的应用程序进行重放攻击;令牌可以作为令牌传递id_token_hint给OIDC认证服务器;令牌向攻击者提供有关用于对其进行签名的密码的信息;等
avejidah

3

解决此问题的一种方法是考虑风险或损害的程度。

您是否正在构建没有用户的应用程序,POC / MVP?您是一家需要迅速进入市场并测试您的应用程序的初创公司吗?如果是的话,我可能只会实施最简单的解决方案,并专注于找到适合市场的产品。使用localStorage往往更易于实现。

您是在构建具有许多日常活动用户的应用程序v2还是人们/企业严重依赖的应用程序。被黑客入侵意味着恢复空间很小还是没有?如果是这样,我将认真研究您的依赖关系,并考虑将令牌信息存储在仅HTTP的cookie中。

同时使用localStorage和cookie / session存储各有利弊。

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

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

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


1

localStorage或httpOnly cookie都不可接受吗?关于受损的第三方库,我所知道的唯一可以减少/防止敏感信息被盗的解决方案是强制执行Subresource Integrity

子资源完整性(SRI)是一项安全功能,使浏览器可以验证是否已交付获取的资源(例如,从CDN获取的资源)而没有意外的操作。通过允许您提供已获取资源必须匹配的加密哈希来工作。

只要受感染的第三方库在您的网站上处于活动状态,键盘记录程序就可以开始收集信息,例如用户名,密码以及您在网站中输入的任何内容。

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


-10

只要对令牌进行加密,就可以安全地将其存储在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


@HassanAlthaf您在这里缺少要点,永远不会有100%安全的证明应用程序,仅此而已,您正在减少攻击面,至少env文件不会直接在github上发布。而且,捆绑的代码将被混淆和破坏,使攻击者很难找到它们。
Kidali Kevin

私钥不应公开。您将损害整个API。
哈桑·阿尔萨夫

根据我的经验,如果您以明智和正确的方式进行操作,则您的私钥将不会在生产版本中公开,如果是这样,请截屏以支持此甚至URL。
Kidali Kevin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.