Javascript - 客户端加密/密钥存储

信息安全 网页浏览器 javascript 密钥管理
2021-09-07 08:26:47

我意识到这通常被描述为一个坏主意。所以首先我会陈述动机 - 随时批评这一点。

为倾向于过度关注安全性的行业创建产品。产品需要存储和返回用户文件,但它们不需要是服务器端可读的。

我觉得通过加密客户端会减少客户所需的信任。他们的机密数据只会被他们可以检查和监控的 JavaScript 触及。这也意味着任何允许访问存储数据的服务器端安全问题都不会导致客户端文档可用(如果他们可以修改提供的 JS 则除外)。

我理想的解决方案是——

- Key generated and injected to all clients users by clients IT team.
- JavaScript uses key to encrypt documents client side. These are then sent to the server and stored.
- On retrieval documents are decrypted again client side.

似乎有几个库支持客户端加密。但是目前我看不到为用户持久存储密钥的方法。理想情况下,这与将证书添加到浏览器存储中的方式类似——即它们可以被注入一次。

有没有人有什么建议?

4个回答

(要明确:这仅在攻击者仅获得只读访问权限的情况下保护用户,并保护未使用该站点的用户,因为攻击者将 javascript 替换为恶意版本。它不能保护用户免受您的恶意从一开始,除非用户煞费苦心地验证/记录您的网站提供的所有 javascript。如果最后一部分对您很重要,则可能有一种方法可以使用 ServiceWorkers 在执行您网站的 javascript 的新版本时提醒用户等,但这是另一个问题。)

您可以使用 localStorage 或 IndexedDB 在客户端本地存储加密密钥。加密密钥可以是您的客户端 javascript 使用的字符串。

在支持的浏览器上,为了提高安全性,您可以改用 Web Crypto API (+ IndexedDB)。使用 Web Crypto API,您可以在 javascript 中生成密钥并将其用于加密/解密,但 javascript 代码无论如何都无法访问原始密钥材料。这意味着即使攻击者有一天可以访问您的服务器并将 javascript 替换为恶意版本,他们也无法将其替换为泄露用户密钥的版本。(但是,他们可以将其替换为使客户端下载文件、解密文件并在下次访问该站点时在后台将其上传回服务器的版本。这需要时间,并且可能会引起用户注意和/或您,因此它可能会给您足够的时间在所有用户数据泄露之前修补问题。)

如果使用来自 openpgp.js 的非对称加密,则私钥默认加密存储,然后短暂解密以使用用户密码解密或签署消息。

它永远不会以未加密的方式存储,并且依赖于用户记住他用来创建密钥对的密码。

在这种情况下,即使黑客找到了私钥,如果没有密码,它们也是无用的。

缺点是我们必须训练用户将他的密码安全地存储在某个地方!

如果您控制服务器端源代码:

我的建议是您在轮换的后端和用户对称加密服务器端存储至少 4 个密钥,然后执行所有加密和解密服务器端。

我有类似的用例,我的工作流程是(使用 fernet 加密):

  • 用户上传数据,然后使用 10 个(旋转)密钥中的 1 个对其进行加密,然后存储在数据库中

  • 在我从数据库中获取 if 然后解密并将其发送到前端后进行查询

好处:

  • 更安全然后处理前端的任何密钥

  • 如果数据库通过 SQL 注入被利用,则它不是纯文本

缺点:

  • 需要更多服务器端资源,因为它会减慢进程

  • 密钥仍然是纯文本服务器端,因此如果主机受到威胁,那里没有任何帮助,但攻击者仍然需要多 1 步才能获取数据。

如果您不控制服务器端代码:

您可以做的最好的事情是将对称密钥存储在数据库中,并在用户注册时为每个生成一个。登录后将其保存在 cookie 中作为该用户的会话

好处:

  • 易于实施

  • 如果一个用户帐户被泄露,则每个用户都有自己的对称密钥,其他用户的数据无法解密

缺点:

  • Cookie 可能会被盗,因此不需要 iframe 标头

  • 如果不使用 HTTPS 和 HSTS mitm 攻击可以轻松获取数据

但是不要把我的建议当作圣杯等待和研究更多的来源,然后由你来决定。;)

我觉得通过加密客户端会减少客户所需的信任。他们的机密数据只会被他们可以检查和监控的 JavaScript 触及。

这不是真的。没有一个普通人可以真正检查和监控浏览器从站点下载的 javascript,如果我足够信任服务器/服务器管理员/服务器软件开发人员,相信他们不会向我发送带有后门的 javascript,我也不妨相信他们会存储我的文件。

我同意这是一个额外的安全层,但它很容易被剥离,以至于实施它似乎几乎毫无意义。它确实可以防止某些威胁场景——例如,它可能会保护未擦除的备份或旧硬盘不会泄露客户的数据——但它确实不会降低客户对服务提供商的信任度。

但是目前我看不到为用户持久存储密钥的方法。

如果您不想将其存储在客户端浏览器存储中,您可以

a) 让用户向客户端 javascript 提供密码,用密码和强对称密码对密钥进行对称加密,并将密钥发送到服务器以存储在那里

b) 将钥匙显示为二维码,并让用户用他/她的手机拍照。当您需要密钥时,用户可以将二维码解析的密钥字符串复制粘贴回客户端 JavaScript 应用程序。不过,这非常麻烦。