ama*_*ter 7 security cookies local-storage node.js jwt
我正在构建一个 node.js web 应用程序,对 GUI 和 graphQL 做出反应,与 Apollo 一起提供后端连接到 AWS 上的 RDS (MySQL) 实例。
我正在对用户进行身份验证,然后返回 JWT。我已经弄清楚如何更新/过期令牌,但现在我面临的问题是当用户访问该站点时将它保存在客户端的何处...
有两个主要概念,第三个是混合模型。1) 如HowToGraphQL所述,使用 JavaScript 将其存储为 localStorage 2) 将其存储在 Cookie 中,并将 http-only 设置为 true,如上述文章中所述,作为对 Randall Degges的阳离子引用
还有另一种方法可以将它仅存储在客户端的内存中,但是每次刷新页面时用户都必须登录,因为它不会在任何地方持久存在。
只有当存在另一个 XSS 漏洞已经被利用时,概念 1 才容易受到 XSS 攻击。但它仅对站点是安全的,因此只有在站点上运行的脚本才能访问它,而不能访问任何站点上的脚本。有很多安全讨论认为它不应该以这种方式存储,即使这是常见的方式,因为开发人员不能信任他们在其站点上运行的每个 JavaScript 脚本,并且可能有一个读取 localStorage 然后将其发送到异地.
概念 2 通过声明 http-only 使其只能被您站点上的服务器访问,从而消除了易受 XSS 攻击的漏洞。这里的问题在于,必须创建一个单独的方法来将相同的后端身份验证用于其他用途,例如标准 API(用于本机应用程序或其他站点),其中 JWT 通过 https 发送到标头中安全地在另一台服务器上。
所以我研究并发现了 Ben Awad 描述的这种混合方法3) 使用请求令牌和刷新令牌。然后,请求令牌可以正常用于标准 API,但在我们的 React 应用程序站点上,我们也可以仅将其存储在内存中,并将刷新令牌存储在 cookie 中,以便在用户刷新或关闭并重新打开浏览器时发回请求令牌。
所以理论上,最好的解决方案是概念 3,它解决了所有问题,但设置起来当然更复杂。
我的问题:我应该如何担心向 XSS 漏洞开放 JWT?当我有更多时间时,我会在很长一段时间内完成这项工作,但我正在争取一个截止日期。我的网站将鲜为人知,而不是像 Facebook 或 Sales-Force 这样的黑客必然瞄准的网站。我的站点不存储信用卡数据或除基本 CRM 和任务列表之外的其他高度敏感数据。如果我的网站通过其他代码对 XSS 开放,那么在不知道 JWT 的情况下,整个身份验证过程不会通过键盘记录脚本或类似的东西受到攻击。我觉得我会做很多额外的工作来防止可能的威胁,如果发生,整个系统就会受到损害。
这是我花了很多时间研究的问题。如何安全地存储授权令牌。人们在处理这个问题时有不同的策略,所以我将分享对我有用的策略。我的应用程序的用户受到了不同攻击的目标,到目前为止,所有攻击都没有成功窃取任何内容。没有人使用 XSS。
这就是我所做的
最后我选择将授权令牌存储在本地存储中。我工作的应用程序通常在 HTTP 路由之上有 WebSocket 连接,我希望将令牌保存在一个地方并充当单一事实来源。它们都是在浏览器中运行的Web应用程序。我构建的大多数应用程序都使用 JWT。
为什么我这样做
首先为什么我不使用刷新令牌。如果它们的保存方式与实际授权令牌的保存方式相同,则否定了刷新令牌存在的原因,因为攻击者可以使用刷新令牌来获取授权令牌。
假设应用程序受到保护,可以防止攻击者将 JavaScript 注入到您的应用程序中(主要是通过应用程序上的表单和 api),则将令牌存储在 cookie 中不会比本地存储有任何优势。确保所有用户输入都是 JS 注入安全的。除此之外,使用 cookie 时还存在一些必须解决的问题。
还有一个问题是,当其中一个帐户被黑客攻击时,您希望尽快使该令牌失效。JWT默认没有撤销机制。实现此功能会削弱 JWT 的可扩展性,因为检查 JWT 需要调用数据库来了解该用户是否可以执行特定操作。有两种方法可以解决这个问题。一种是如果用户被从数据库中冻结,则只需检查用户数据,由于调用,它的可扩展性较差,但如果您已经将用户数据提取到中间件中,那就足够了TM。另一种方法是在对数据库进行更改或来自客户端的调用很重要时从数据库中提取“用户是否冻结”数据。
总之
我会将令牌存储在本地存储中。保护应用程序免遭代码注入。如果帐户以任何方式受到损害,请为帐户设置终止开关。
编辑感谢 @JerryCauser 的评论
将您的令牌保存在安全的仅 http cookie 中会更安全。不要指望存储机制的选择会自动保护您的用户免遭黑客攻击。有多种方法可以劫持会话和其他漏洞,包括用户使用 Web 扩展并批准其读取受保护数据的请求。
对于下面的投注网站的示例,您不会要求用户在每次下注时写入密码(或通过自动电子邮件批准请求),但您会在每次他们想要提款时要求输入密码。
我使用本地存储,因为即使令牌被盗,或者其他人进入您用户的笔记本电脑(例如孩子),您也不应该让该帐户在未经批准的情况下执行关键任务。
反黑客保护没有灵丹妙药。尽最大努力以常识确保用户的安全。
编辑作为对提问者@amaster 的评论的回答
如果您每次调用都访问数据库,也许 JWT 不是最好的解决方案。JWT 的要点是在不调用数据库的情况下签署声明和用户 ID。在这种情况下,也许选择加入会话而不是 JWT。
小智 5
如果您认为您的站点不能在 Internet Explorer 和一些旧版本的主要浏览器上运行,您可以利用一个名为 Same-Site 的新 cookie 属性(更准确地说,该站点可以运行,但 cookie 将不安全)。
通过将 cookie 定义为 HttpOnly,您可以立即免受 XSS 攻击,但您也容易受到 CSRF 攻击。
现在通过将 cookie 定义为具有属性 Same-Site=Strict,cookie 将仅通过 Http 调用发送,并且仅当域与您站点的域匹配时。因此,例如,如果有人在另一个站点中创建一个表单并尝试向您自己的站点执行发布请求,则永远不会发送 cookie。
如果您希望 cookie 仅在 GET 请求上传递,您可以将 Same-Site 属性设置为 Lax,但正如您所提到的。
您可以在 SameSite cookie 部分下的以下链接中找到有关此功能的更多信息:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
您还应该使用以下链接检查该功能的浏览器兼容性:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Browser_compatibility