“浏览器加密鸡和蛋问题”的解决方案?

信息安全 加密 Web应用程序 网页浏览器 javascript 质子邮件
2021-09-02 14:59:14

不时地,此版块中会出现有关使用客户端加密(或“浏览器内”加密)的 Web 应用程序的问题,这些应用程序声称这些应用程序的设计方式使得这些应用程序的操作员拥有“零” -访问'用户的私人信息。请参阅下面几个相关问题的链接。此类应用程序的一个常见示例是Protonmail,它旨在提供端到端的加密电子邮件。 Protonmail 声称“您的数据以一种我们无法访问的方式加密”,并且“数据在客户端使用我们无权访问的加密密钥进行加密”。

在围绕这个主题的讨论中,‘browser crypto chicken-and-egg problem’经常出现。该术语由安全研究员 Thomas Ptacek 于 2011 年创造本质上,问题是:如果你不能信任服务器提供你的秘密,那么你怎么能信任服务器提供安全的加密代码?以 Protonmail 为例,有人可能会争辩说,流氓 Protonmail 服务器管理员(或已获得对 Protonmail 服务器的访问权限的攻击者)可以更改 Protonmail 服务器提供的客户端 JavaScript 代码,以便该代码捕获用户的私钥或明文信息并将这些秘密发送回服务器(或其他地方)。

这个问题是:可以使用以下方法解决“浏览器加密鸡蛋问题”吗?

  1. Web 应用程序设计为单页 Web 应用程序静态网页在用户会话开始时提供,并且该静态页面在整个用户会话期间保持加载在用户浏览器中。像 Protonmail 一样,所有的加密都是在浏览器中完成的——用户的明文秘密和私人加密密钥永远不会离开浏览器,只有密文被发送到服务器。然而,与 Protonmail 不同,Protonmail 在用户每次操作后由服务器动态生成一个新页面——用户的请求通过客户端AJAXXHR调用从静态页面发送到服务器,并且使用服务器对这些调用的响应来更新静态页面。

  2. 静态页面依赖的所有支持文件(例如 javascript 文件、css 文件等)都由静态页面使用子资源完整性引用

  3. 用户的私有加密密钥(或从中派生出私有密钥的密码)由用户存储。用户通过静态页面上的界面输入他们的私钥(或密码),然后将密钥传递给在浏览器中运行的客户端脚本。所有浏览器内加密都由浏览器的本机Web Crypto API 处理

  4. 为了缓解 XSS 攻击,所有外部内容在写入静态页面之前都在客户端脚本中进行了清理;所有外部内容都使用元素的 .innerText 属性(与 .innerHTML 相对)写入静态页面元素,并且应用了严格的内容安全策略(CSP),禁止使用内联脚本。

  5. 受信任的审阅者 (TR) 审阅静态页面和所有支持文件。TR 确定客户端代码“如广告”,并且客户端代码在任何时候都不会将用户的秘密发送回服务器(或其他任何地方),并且在任何时候静态页面都不会请求新页面来自服务器,并且以上所有内容都已正确实施。然后 TR 用他的私有签名密钥对静态页面进行签名并将签名公开。

  6. 用户将他的浏览器指向静态页面。然后,用户单击其网络浏览器上的“页面另存为”功能,以将静态页面(当前加载在他的浏览器中)保存到他的系统中。他使用 TR 的公钥验证 TR 在静态页面上的签名。如果签名被验证,那么用户通过已经加载在他的网络浏览器中的静态页面继续使用该服务。

总结一下:经过 TR 审核和签名的静态页面在整个用户会话期间始终加载在用户的浏览器中,并且在任何时候都不会被服务器的新页面替换。用户在其会话开始时通过使用 TR 的公钥验证该页面的 TR 签名来验证静态页面的完整性(以加密方式,以类似于通常验证可下载文件的完整性的方式)。[如果浏览器(或者浏览器扩展)有一个内置的方法来执行这个功能会很好,但是在那一天到来之前,上面第 6 步的过程就足够了]。在步骤 2 中使用子资源完整性 (SRI) 可确保攻击者无法修改支持文件,因为这样做会破坏 SRI 检查,或者需要更改根文档,

对于这个问题,假设 TR 有能力执行手头的任务,并且用户有一种可靠的方法(例如,通过受信任的第三方或一些带外方法)来验证 TR 的公钥是否真实和正确. 另外,为了这个问题,请抛开旁道攻击的可能性,例如浏览器漏洞、TR 设备或用户设备被盗、TR 私钥或用户私钥被盗等。

鉴于上述情况,您能想出某种方式让流氓服务器管理员(或已获得服务器访问权限的黑客)能够窃取用户的秘密,如果可以,怎么做?

有关的:


2021 年 2 月 27 日编辑

为 Firefox开发了一个小型浏览器扩展,结合了这个问题中的许多想法以及以下答案和回复,旨在解决这个问题。有关更多信息,请参阅下面答案

4个回答

首先,正如我在问题下的评论中提到的,如果用户运行任何修改页面源的浏览器扩展程序,则此方法将不起作用,因为签名将不再保持有效。这也适用于拦截脚本并将其注入网页的防病毒软件。可以轻松禁用浏览器扩展,但在某些情况下可能无法禁用防病毒软件。

其次,虽然这个程序在使用笔记本电脑/台式机时可以工作,但让它在智能手机上工作会更加麻烦,甚至几乎不可能。据我所知,在 iOS 的浏览器中,没有简单的方法可以将网页保存为 html。

最后,要回答所提出的问题,服务器似乎确实有办法加载页面的恶意版本。HTTP Refresh 标头是一个非官方标头,但似乎受到许多浏览器的支持,它可能允许服务器将用户重定向到恶意页面。通过提供原始页面并设置刷新时间,比如 5 分钟,服务器可以合理地确定刷新发生在用户验证页面完整性之后,然后希望用户不会注意到重定向。由于这是作为标头发送的,因此不会影响原始页面的完整性,并且签名将保持有效。

基于这个问题的想法和对这个问题的回答,我为 Firefox 开发了一个小型浏览器扩展(称为Page Integrity),用于验证包含浏览器加密代码的网页的完整性。

页面完整性显示 https://www.pageintegrity.net/signedpage.html 示例页面的完整性信息。 页面完整性显示https://www.pageintegrity.net/signedpage.html示例页面的完整性信息显示页面源的 SHA-256 校验和哈希。该页面还使用三个签名进行签名 - 还显示了这些签名的签名者的公共签名密钥。

单击浏览器工具栏中的按钮会在浏览器的活动选项卡中显示有关当前加载页面的完整性信息,包括页面源的 SHA-256 校验和哈希。此外,如果页面源使用一个或多个数字签名进行签名,PI 将验证签名,并显示签名者用于这些签名的公共签名密钥。

有关详细信息,请参阅https://www.pageintegrity.net/

可以通过浏览器扩展来做到这一点,用户无需下载已签名的 Web 应用程序并在本地运行。

由于您已经有一个受信任的审阅者/受信任的第三方来进行代码审查并签署 Web 应用程序以及所有(传递)子资源。他们还可以发布动态验证的浏览器扩展。检查的哈希值可能内置在扩展中或从 TTP 的服务器定期下载。

为此类浏览器扩展提供了许多挂钩来控制请求的执行。问题是浏览器在请求尚未完成时立即开始执行代码。这意味着 Web 应用程序必须以这样一种方式编写,即在接收并验证请求后开始执行。验证可以通过这个(如果它在任何地方实现;还没有测试过)或通过在onCompleted回调之后读取页面内容来完成。

问题是这可能还不够。如果 Web 应用程序行为异常,它可能不会等到请求完全加载并开始将数据发送到其他地方。通过扩展实施的 CSP 策略可能是实现目标的方法。此外,扩展程序可能会阻止(通过webrequest API)来自网络应用程序的任何网络请求,直到它得到验证。如果验证失败,扩展程序可以关闭选项卡并打开一条通知,说明 Web 应用程序源以意外方式更改,这可能意味着操作员试图偷偷摸摸或只是其他扩展程序操纵了源。

遗憾的是,似乎无法通过扩展 API 查看实际收到的响应,这意味着 Web 应用程序可能会通过运行一些 JavaScript 并立即删除一些 JavaScript 已执行的证据来偷偷摸摸。只要页面未经验证,我不确定是否有办法在短时间内禁用 JavaScript。

如果这是可以解决的,那么您已经添加了三个更受信任的第三方,因为您现在信任 Google、Apple 和 Mozilla 作为其各自 Web 扩展商店的运营商。

如果可行,这将具有出色的用户体验,因为 TR 可以查看 Web 应用程序的新版本,并将相应的哈希添加到扩展中以进行验证。

我读了这篇关于信号假装他们可以使用 SGX 的文章,因此 A 可以远程断言 B 运行受信任的代码:https ://signal.org/blog/secure-value-recovery/

我不知道他们是否找到了新的理论概念,或者这只是一堆保护,希望它们不会全部脱落。技术细节并非微不足道。

你认为这可能是一个解决方案吗?