【问题标题】:How to store RSA private keys in the client's browser for better UX?如何在客户端的浏览器中存储 RSA 私钥以获得更好的用户体验?
【发布时间】:2016-01-16 21:46:36
【问题描述】:

我正计划编写一个基于 Web 的密码管理软件,以便在团队组和成员中提供共享和权限功能。

编辑:

正如下面 Luke Park 所提到的,我想补充一点,我正在使用带有令牌(过期)的用户密码授权。令牌在所有授权的 API 调用中提供,使得这些调用只能由注册用户访问。是的,应用程序由 SSL 封装,使服务器和客户端之间的通信更加安全。

编辑结束

目前我已经做了很多关于寻找正确的密码加密处理模式的研究。我正在研究的模式称为混合加密,因为它适用于多个客户端并且可以安全地实施。以下是我将如何在我的应用程序逻辑中实现此模式:

客户想要创建密码

  1. Andre 创建密码并以纯文本形式提供密码
  2. 前端应用程序生成一个对称密钥,称为会话密钥
  3. 客户端使用会话密钥加密明文密码
  4. Andre 选择将密码分享给 Bob
  5. 客户端通过 REST 从服务器应用程序中检索 Bob 的公钥
  6. 客户端使用 Bob 的公钥加密会话密钥
  7. 客户端将加密的会话密钥和加密的密码传输到服务器

服务器应用程序处理密码提交

  1. 服务器应用程序使用只有服务器应用程序知道的私有盐对数据进行加密
  2. 服务器将数据存储到数据库中

检索共享密码

  1. Bob 请求 Andre 最近共享的密码
  2. 服务器使用私有盐解密请求的数据集并将其发送给客户端
  3. 客户端使用 Bob 的私钥(由 Bob 的计算机提供)解密会话密钥
  4. 使用解密的会话密钥,客户端现在可以解密密码(例如现在可以复制)

到目前为止,我认为这种模式足够安全,因为客户端的所有私钥都不是公开的,并且只对客户端可见。为了在基于 Web 的应用程序中实现这一点,我发现 openpgpjs.org 可以在客户端生成公钥和私钥,并使用这些密钥加密或解密数据。最重要的是,私钥字符串可以通过秘密密码保护。

我的问题是,如何在不影响用户体验的情况下将私钥文件实现到我的前端应用程序中?我不想强迫用户手动管理他的私钥并强迫他在每个密码请求上提供密钥。将私钥文件存储到浏览器的本地存储中并在每次密码请求时从本地存储中获取私钥是否安全?

【问题讨论】:

  • 这一切都很好。但对我来说,将密码存储在网络环境中的想法听起来很荒谬。
  • 只要加密足够安全,它是一个Web应用程序这一事实并不会显着影响整体安全性。另外,我不打算提供 SASS 实现,而是提供安全的自托管应用程序,例如可以在本地进行管理。
  • Web 环境的问题是,作为用户,我无法检查我正在使用的内容。与本地安装的实用程序不同,我无法检查代码,因为每次访问该实用程序时都会重新加载它。根据定义,这是我无法信任的情况。 “网络”是个好东西。但它不是可以很好地替代所有东西。
  • 我同意你对信任因素的看法,但是这个应用程序有一个非常特定的目的,并且不会针对那些不信任它的人。
  • 没有人可以信任它。 :-) 除了(也许)服务提供商。

标签: javascript security web cryptography password-protection


【解决方案1】:

您仍然无法验证您的客户端和服务器。因为任何人都可以公开请求公钥,所以很容易在客户端和服务器之间进行 MITM,并为其提供垃圾任意密码。

考虑:

  • 攻击者使用 REST 检索 Bob 的公钥。
  • 攻击者生成自己的“会话密钥”并加密一些任意值。
  • 攻击者将结果提供给一直处于中间人地位的客户。
  • 客户端认为它收到了正确的密码,但没有。

如果无法验证和授权服务器和客户端,您的系统就很容易被弄乱。这似乎不是一个大问题,但它很容易为其他攻击让路。

编辑:还注意到,如果在客户端和 REST API 之间发生 MITM,攻击者可以向客户端提供与攻击者拥有的私钥配对的公钥。

考虑:

  • 客户端即将与服务器共享其密码。
  • 客户端联系 REST API(MITM 攻击者)以提取 Bob 的公钥。
  • 攻击者提供他们的公钥。
  • 客户端生成会话密钥和密码的密文。
  • 客户端将结果发送给“服务器”(攻击者)。
  • 攻击者使用他们的私钥来检索会话密钥。
  • 攻击者使用会话密钥检索明文密码

【讨论】:

  • 感谢您指出这一点。但是,我确实使用基于用户密码的授权来访问在每次登录时生成会话令牌的应用程序。这是否可以防止您提到的安全问题?我确实这么认为,因为 REST API 调用无法公开访问。
  • 如何保护客户端和服务器之间的这些用户密码通信以访问 REST 服务?你需要小心,否则你最终会陷入军备竞赛。
  • @user3577183 另外,请参阅我上面的编辑。
  • 现在我已经在 server-api 上实现了一个 verifyPassword 方法,它将生成一个带有过期日期的 JWT 令牌。 (github.com/auth0/node-jsonwebtoken 是我正在使用的库)。访问令牌稍后可以在 HTTP 标头之间传递。每个授权调用都会检查令牌是否已过期或有效。
  • @user3577183 但是这种通信是在某个安全层下吗? SSL?对称加密等?如果是纯文本,则根本无法解决问题。
【解决方案2】:

经过深思熟虑后,我决定使用用户主密码加密 RSA 私钥。由于主密码没有存储在任何地方,我假设将加密的私钥存储到用户的本地浏览器存储中是安全的。这个解决方案可以在每个密码请求上自动提供加密的私钥,但强制用户在每个请求上输入他的密码,这对我来说现在很好。

如果有人有更好的解决方案,如果你能在这里发布你的解决方案,我会很高兴。

【讨论】:

    【解决方案3】:

    老实说,整个“使用会话密钥作为对称加密令牌”场景对我来说似乎有点多余。也许它会增加一定程度的模糊性,但传递加密数据 + 加密令牌的整个想法对我来说似乎有点奇怪。

    我也会尝试重新考虑一下设置。最后,这是我们说的基于Web的应用程序,通过ACL和密码权限访问不是更简单吗?

    创建密码

    1. Bob 创建明文密码
    2. 应用程序使用 Bob 的公钥(登录时获得)加密密码
    3. 应用程序使用 JWT 通过 REST 保存加密密码(登录时获得)

    找回密码

    1. Bob 试图以明文形式查看他的密码
    2. 应用程序使用 JWT(登录时获得)向 REST 发出请求,请求 Bob 的私钥
    3. 应用程序接收私钥,解密密码并显示。

    共享密码

    1. Bob 决定与 Mark 共享他的一个密码(假设每个密码旁边都有一个名为 SHARE WITH MARK 的神奇按钮)
    2. 应用程序使用 Bob 的公钥加密 Mark 的用户令牌
    3. 应用程序使用 JWT(登录时获得)向 REST 发送请求,发送 Mark 的加密用户令牌
    4. REST 应用程序接收请求,使用 Bob 的私钥解密 Mark 的用户令牌
    5. REST 应用程序为 Bob-Mark 关系创建新的 RSA 对,其中 Bob 是提供者,Mark 是接收者
    6. REST 应用程序在 Mark 的用户令牌下创建新密码,并使用这个新的 RSA 对加密它

    TL;TR

    请勿共享密码本身。相反,在 ACL 上投入一些时间并为用户对(提供者 + 接收者)生成新的 RSA 对。更进一步的方法是为共享密码创建特殊表 - 它会更干净,并且在处理撤销权限时也会让人头疼。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-11
      相关资源
      最近更新 更多