在 HTML5 本地存储中存储加密密码有多安全?

信息安全 密码
2021-08-20 04:23:29

背景

我正在尝试开发一个 Web 应用程序,用户将能够使用他们的密码“P”登录,并且在登录时可以创建一个主密码“MP”。MP 可用于打开/关闭一个保管库(很像密码管理器),用户可以在其中存储敏感信息。在对该主题进行一些研究后,我决定确保以下几点:

  • 主密码 MP 从不存储/发送到服务器
  • 所有加密/解密都在客户端进行(在我的情况下是浏览器)

现在,当我将密钥 MP'(定义如下)存储在内存中时,每次刷新浏览器或用户在新选项卡上打开站点时,保险库基本上都会关闭。只要用户愿意,我怎样才能让保险库保持打开状态?Cookie 不是解决方案,因为它会导致 MP' 在每次请求时都发送到服务器;但是,HTML5 本地存储可能是一种可能性

现在,如果黑客碰巧访问了本地存储,他们将获得 MP' 并可以使用它解密所有敏感信息。作为解决方案,这是我的想法:

  1. 打开保管库时,客户端向服务器请求一次性随机密钥“Rk”
  2. 服务端生成Rk,存储在用户的会话中并发回给客户端
  3. 客户端使用Rk加密MP′得到MP′′
  4. MP'' 存储在 HTML5 本地存储中,而 Rk 保存在内存中
  5. 需要时可以使用 Rk 解密 MP'' 并用于后续操作
  6. 在浏览器刷新时,客户端从服务器重新获取 Rk(服务器只是返回已经存储在会话中的 Rk)
  7. 如果用户明确关闭保管库或通过注销结束会话,则 Rk 已过期

问题

这个解决方案的安全性如何?我缺少任何明显的警告吗?修复它的理想方法是什么?

补充笔记

为了您的理解,这里简要概述了我计划如何满足我的需求:

  1. 用户创建一个新的 MP
  2. MP 使用密钥拉伸算法加密以产生 MP'
  3. MP′作为密钥对已知值V进行加密得到Vh(显然V≠MP或MP′)
  4. Vh 根据用户记录存储在服务器上

Vh 有两个目的:

  1. 表示用户已经创建了MP。如果还没有,我可以要求用户创建一个新的
  2. 每当用户输入 MP 打开保险库时,我都可以从服务器检索 Vh 并尝试使用 MP' 对其进行解密。如果解密成功,我假设用户输入了正确的MP

正如您可以想象的那样,其余部分应该如何工作:

每当用户想要存储/检索敏感信息时:

  1. 他们使用 P 登录并使用 MP 打开他们的保险库
  2. 如前所述,客户端产生 MP'
  3. 敏感信息在发送并存储在服务器上之前使用 MP' 加密
  4. 根据用户需要,从服务器检索加密的敏感信息(原样)
  5. 客户端使用 MP' 解密数据
2个回答

您的方法有几个问题:

1) 前向保密。假设攻击者可以监控通信(通过被黑的公司 https 代理或其他方式)。稍后,用户删除该帐户并显示 MP,因为他认为它没用。使用记录的数据和 MP,攻击者可以恢复所有信息,因为您正在使用 MP' 加密保险库。

2)目前尚不清楚您如何防御 P 的入侵。捕获 P(通过网络)攻击者可以登录,获取Rk并解密 MP”,除非在所有登录时重新生成 Rk,否则意味着用户将有效如果她关闭浏览器就退出(这可能是好的和有意的,我不知道)。无论如何,最好不要发送 P(见下面的想法)。

3) 加密会给你有限的安全改进。如果攻击者可以访问 localStorage,那么她可能具有物理访问权限和/或破坏了您的机器,因此无论如何您都注定要失败(您将面临键盘记录器、本地脚本注入等)。如果硬盘被盗或攻击者能够伪造您的域(例如 DNS 缓存中毒),加密将为您提供帮助。最好不要一开始就存储密码。

几个想法:

  • 减轻 (1) 使用一次性会话密钥来加密所有消息。例如,您可以使用非对称加密向服务器发送一些随机会话密钥(使用服务器的公钥加密)。或者,您可能希望强制执行正确的 SSL 会话(通过通知和教育您的用户),因为 SSL 具有良好的前向保密性。

  • 对于(2),不要使用 P 进行身份验证,而是使用一些高级方法,例如。OAuth,最好是 2FA。

  • 您可能会考虑使用 sessionStorage 而不是 localStorage 保证在浏览器重新启动时被删除(其他方式它与没有网络的 cookie 非常相似)。我不确定所有(或任何)实现是否可以在退出时安全地删除所有存储痕迹,因此加密仍然可能是一个好主意。

我认为可能值得重新评估您的前提。大概你想加密客户端的东西,这样服务器就无法访问未加密的数据,但事实并非如此,我认为它最终比实际安全更安全。

是从 2011 年开始的,但我认为这里的主要问题仍然是相关的,如果您不能信任服务器能够正确处理数据加密(即加密然后忘记明文和密码),那么您如何信任它来提供应该处理加密客户端的代码?

在允许攻击者在不修改请求的情况下读取请求的妥协情况下,这似乎是有益的,但是您仍然对服务器非常信任,我不相信这是值得的。