Answers:
在大多数现代单页应用程序中,我们确实必须将令牌存储在客户端的某个位置(最常见的用例-在页面刷新后使用户保持登录状态)。
共有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。
我知道这是一个老问题,但是根据@ 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由社区维护,并且不包含恶意代码;如果不确定,您可以自由进行审查。
HttpOnly
SameSite=strict
和的cookie secure
,将使您在cookie中设置的信息保持安全。然后针对XSS,只需确保您的JavaScript不知道任何与身份验证相关的数据,例如令牌和密码(即不要将它们存储在Web存储中)-如果导入恶意脚本,则该脚本将无权访问对敏感数据。是的,您也无法通过JS访问令牌,但这确实不是问题。
基本上,可以将JWT存储在localStorage中。
我认为这是个好方法。如果我们谈论的是XSS,使用CDN的XSS,那么也存在潜在的风险,也可能会导致客户登录/通过。将数据存储在本地存储中至少可以防止CSRF攻击。
您需要了解两者并选择所需的内容。两种攻击都不是您需要了解的全部,只需记住:您的整个应用程序的安全性仅与您应用程序的最低安全点相同。
再一次存储就可以了,容易受到XSS,CSRF等的威胁。
如果使用CDN,则不安全:
恶意JavaScript可以嵌入到页面中,并且Web存储受到损害。这些类型的XSS攻击可能会导致所有人在不知情的情况下访问您站点的Web存储。这可能就是为什么许多组织建议不要在Web存储中存储任何有价值的东西或信任任何信息的原因。这包括会话标识符和令牌。
通过暴风雨
您从外部需要的任何脚本都可能受到威胁,并可能从客户端的存储中获取任何JWTS,并将个人数据发送回攻击者的服务器。
本地存储被设计为可通过javascript访问,因此它不提供任何XSS保护。如在其他答案中提到的那样,有很多方法可以进行XSS攻击,默认情况下,本地存储不受此方法的保护。
但是,Cookie具有安全标记,可以防止XSS和CSRF攻击。HttpOnly标志可防止客户端javascript访问cookie; Secure标志仅允许浏览器通过ssl传输cookie; SameSite标志可确保将cookie仅发送到源。尽管我刚刚检查过,Opera和Chrome当前仅支持SameSite,但是为了避免受到CSRF的影响,最好使用其他策略。例如,在另一个包含某些公共用户数据的cookie中发送加密令牌。
因此,cookie是用于存储身份验证数据的更安全的选择。
id_token_hint
给OIDC认证服务器;令牌向攻击者提供有关用于对其进行签名的密码的信息;等
解决此问题的一种方法是考虑风险或损害的程度。
您是否正在构建没有用户的应用程序,POC / MVP?您是一家需要迅速进入市场并测试您的应用程序的初创公司吗?如果是的话,我可能只会实施最简单的解决方案,并专注于找到适合市场的产品。使用localStorage往往更易于实现。
您是在构建具有许多日常活动用户的应用程序v2还是人们/企业严重依赖的应用程序。被黑客入侵意味着恢复空间很小还是没有?如果是这样,我将认真研究您的依赖关系,并考虑将令牌信息存储在仅HTTP的cookie中。
同时使用localStorage和cookie / session存储各有利弊。
如第一个答案所述:如果您的应用程序具有XSS漏洞,则两者都无法保护您的用户。由于大多数现代应用程序具有十几个或更多不同的依赖关系,因此越来越难以保证应用程序的一个依赖关系不受XSS攻击。
如果您的应用程序确实存在XSS漏洞,并且黑客能够利用它,则该黑客将能够代表您的用户执行操作。黑客可以通过从localStorage检索令牌来执行GET / POST请求,或者如果令牌存储在仅HTTP的cookie中,则可以执行POST请求。
将令牌存储在本地存储中的唯一缺点是,黑客将能够读取您的令牌。
localStorage或httpOnly cookie都不可接受吗?关于受损的第三方库,我所知道的唯一可以减少/防止敏感信息被盗的解决方案是强制执行Subresource Integrity。
子资源完整性(SRI)是一项安全功能,使浏览器可以验证是否已交付获取的资源(例如,从CDN获取的资源)而没有意外的操作。通过允许您提供已获取资源必须匹配的加密哈希来工作。
只要受感染的第三方库在您的网站上处于活动状态,键盘记录程序就可以开始收集信息,例如用户名,密码以及您在网站中输入的任何内容。
httpOnly cookie将阻止从另一台计算机进行访问,但不会阻止黑客操纵用户的计算机。
只要对令牌进行加密,就可以安全地将其存储在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