【数据加密】端到端加密:如何在web应用程序中加密数据

视频号

微信公众号

知识星球

Chinese, Simplified

在本文档中,我们讨论了在web环境中进行端到端加密的指导原则,以通过使服务器对加密数据视而不见来确保用户隐私。我们还提供了一个性能基准来评估加密的影响,具体取决于用户设备和数据大小。

介绍

端到端加密,引用自维基百科,是:

只有通信用户才能阅读信息的通信系统

例如,Signal和ProtonMail都使用端到端加密,其中端指的是用户:这保证了除了通信用户之外,没有人可以读取交换的数据。

这有时也被称为客户端加密,而不是服务器端加密,特别是因为当端实际上是服务器时,“端到端”术语有时会被误导性地使用。在这种情况下,数据在客户端和服务器之间被加密,但可以由后者解密。

在本文档中,end指的是用户的设备:目标是以服务器无法解密的方式加密应用程序中的数据。但为了避免任何混淆,我们将在下面使用“客户端加密”术语。

这些通用指南是在个人云环境中制定的,用户(我们称她为Alice)信任服务器正确管理她的数据并提供预期的服务。但她并没有给予它无条件的信任,尤其是对私人数据,如私人图片、机密文件、密码等。事实上,Alice知道,即使服务提供商遵循安全良好做法,并且在用户隐私方面似乎是可靠的,但任何服务器都可能被破坏,用户数据也可能泄露。

因此,我们假设服务器是半可信的威胁模型,即它将诚实地运行服务,不会试图偏离预期的计算,但可能会访问来自合法交易所的信息。请注意,这种威胁模型在垃圾堆中被认为是诚实但好奇的(见本文中的定义1)。

⚠️ 这并不意味着服务器有意对用户数据感到好奇。例如,舒适云对隐私非常谨慎,不会泄露任何用户数据。然而,如前所述,任何服务器都可能被破坏:因此,我们试图将服务器端的数据公开减少到最低限度。此外,值得注意的是,任何托管提供商实际上都可以运行Cozy服务器,因为代码是开源的。授予托管提供商的信任可能会有所不同,人们可能希望将敏感数据排除在服务器之外:端到端加密可以帮助实现这一点。

在本文中,我们提出了一个完整的端到端加密方案,从用户身份验证到加密数据的检索。我们特别关注可用性和可行性,因为我们认为这对加密的整体采用至关重要;安全性,尤其是加密,通常完全在技术方面掌握,很少或根本不考虑用户体验。

因此,我们没有追求最好的理论加密协议,而是更倾向于做出务实的选择,在现实世界的攻击场景中使用最先进的安全性来应对我们的威胁模型。

我们没有对要加密的数据类型做出任何假设,这些数据可以是图片、文本文件、密码等。然而,根据数据大小,可能会出现一些性能问题:因此,我们在一个名为Cozy Drive的开源文件管理应用程序中制定了一个基准,根据文件大小对实际加密影响提供了一些见解。

最后,值得一提的是,我们并没有重新发明轮子并构建自己的加密系统(这在密码学中总是一个坏主意),而是从使用客户端加密的现有行之有效的解决方案中获得了灵感,尤其是密码管理器,如1Password、LastPass或Bitwarden,存储系统,如Tresorit,或电子邮件服务,如ProtonMail。

⚠️ 本文件撰写于2020年上学期,反映了这一时期的知识。某些部分可能已经过时,这取决于实现的演变、最先进的进展等。

基线

  • P:用户密码
  • Km:从用户密码派生的主密钥。
  • Hauth:身份验证哈希,根据用户密码计算。
  • Kvault:一个随机生成的AES加密密钥。它由Km加密,并用于加密所有其他加密密钥。
  • Kaes-i:AES加密密钥,随机生成。它由Kvault加密,用于加密用户数据。
  • ivi:初始化向量,用于使加密不具有确定性。这意味着相同的明文不会产生相同的密码。

ℹ️ 用户密码是安全的根本。虽然它有一些已知的缺点(可能被遗忘、被盗、暴力强制等),但这是当今任何用户都知道的主要身份验证方法。已经有很多关于密码生成和最佳实践指南的资源,比如NIST的资源。作为补充,强烈建议启用双因素身份验证。

ℹ️ 密钥和IV生成必须正确进行,以保证加密的稳健性。参见NIST关于密钥生成的建议和IETF关于初始化矢量的备忘录。

❓ 为什么Kvault和Km

这是因为撤销:如果只使用Km,密码更改将迫使所有AES密钥重新加密,如果对许多文档进行加密,这可能是一个繁重的过程。这种间接方式只允许在密码更改后撤销Km并重新加密Kvault。

身份验证

由于密码用于计算加密主密钥Km,因此永远不应将其明文发送到服务器。

身份验证流由以下架构表示:

authentication-flow

加密流程

一旦用户输入了她的密码,就会使用用户电子邮件作为盐,通过密钥推导算法对其进行哈希运算。生成的输出为Km。

然后,Km本身被作为salt与密码进行散列,以生成最终的密码散列。这个散列被发送到服务器,服务器根据它计算一个新的散列,以产生Hauth,即身份验证散列。如果它与数据库中存储的匹配,则服务器授予用户访问权限。

使用此协议,服务器不会了解任何有关用户密码的信息。

ℹ️ 该身份验证协议在很大程度上受到Bitwarden的启发,并在Cozy中进行了实现。

ℹ️ 客户端的密钥推导算法是PBKDF2。我们选择它而不是更现代的算法,如scrypt、bcrypt或argon2,因为它是一种众所周知的算法,通过SubtleCrypto实现,在现代浏览器中得到了广泛的使用和测试,并且本机支持。

在服务器端,我们选择了scrypt,因为它需要大量内存,因此设计成更能抵抗硬件特定的攻击,例如ASIC或GPU。

ℹ️ 迭代次数是一个可调的选择,也是对暴力攻击的鲁棒性和速度之间的权衡。100000是1Password和LastPass使用的值。

ℹ️ 该电子邮件被用作盐,这也是密码管理员Bitwarden做出的选择。任何持久的用户数据都可以使用,只要它足够长以确保唯一性,例如不是名称或邮政编码。在我们的实现中,此电子邮件是从用户域自动构建的。

加密

密钥库创建

加密过程从生成Kvault开始,该密钥将用于加密未来的AES密钥。

encryption-process

密钥库创建

加密

Kvault本身就是一个AES密钥,使用主密钥Km加密。它存储在数据库中,并在用户连接后进行检索和解密。然后,它可以用于加密数据:

encryption

数据加密

每个用户数据都使用专用AES密钥Kaes-i加密,Kaes-i本身也使用Kvault加密。请注意,iv必须始终不同,以使加密不具有确定性。

解密

  1. 当用户想要解密数据时,会执行以下步骤:
  2. 用户输入密码
  3. 计算Km
  4. Kvault由Km检索和解密
  5. 数据i与其关联密钥Kaes-i一起被检索
  6. Kaes-i使用Kvault解密
  7. 数据i用Kaes-i解密

ℹ️ 步骤1到3在会话期间只发生一次。Kvault保存在内存中,因此用户不必每次需要加密/解密时都输入密码。

ℹ️ 对于每个解密步骤,都会检索用于加密的iv。它可以与加密数据一起存储,不需要特定的保护。

密钥重用

Kvault可以用于加密/解密任何数据,只要每次使用不同的iv即可。然而,这可能会在某些加密方案中引入漏洞。

为了说明这一点,让我们假设A和B用相同的密钥K加密(这是一种简化;实际的AES机制实际上比这个例子更复杂):

  • A ⊕ K = A'
  • A ⊕ K = B'
  • A'⊕ B' = (A ⊕ K ⊕ B ⊕ K) = (A ⊕ B) + (K ⊕ K) = A ⊕ B

因此,如果攻击者能够从A中知道一些比特,那么它将能够获得关于B的信息。

也就是说,如果我们假设K=Kaes-iõivi,那么对于两个不同的加密回合,K将永远不会相同,因为ivi总是不同的,这使得我们上面的例子在实践中不可能,因为实际上会有K和K',使得不可能在a和B之间获得任何信息。然而,对不同的数据使用不同的密钥被认为是一种很好的做法,因为如果ivi生成被破坏,它仍然可以保护加密,例如随机生成可能会发生这种情况。

以同样的方式,如果数据被更新,例如图片,则Kaes-i应该被撤销,并且生成另一个密钥Kaes-i以用新的ivi对图片进行重新加密。

数据共享

对每种数据类型使用不同的Kaes-i也可以简化数据共享:如果使用一个Kvault来加密所有内容,则共享将意味着共享Kvault,或者重新加密每个数据以与收件人的公钥共享。

前者在安全性方面是不可接受的,而后者效率不高:与对称加密相比,非对称加密的效率相当低,并且在共享许多和/或巨大文件时会导致严重的性能问题。此外,对共享数据的任何更新都需要使用公钥重新加密。

使用Kaes-i密钥可以简单地将数据密钥共享给接收者,并用他们的公钥加密。因此,接收者能够用他们的私钥解密Kaes-i,用他们自己的Kvault重新加密,并将其与共享数据一起存储。

密钥存储

加密密钥不应不安全地存储在用户设备上,即在没有任何保护的情况下解密。否则,这意味着一个受损的设备将能够解密任何数据。

在移动设备上,可以使用苹果的密钥链或安卓的密钥库。

在桌面环境中,硬盘驱动器可以在操作系统级别加密,也可以在硬件级别加密,例如使用Intel SGX飞地,在那里,密钥将通过直接存储在CPU中的密钥进行安全加密。

不幸的是,在浏览器中,目前没有简单的方法来安全地存储加密密钥;因此,我们强烈反对在浏览器中存储明文密钥。

技术指南

在本节中,我们将提供客户端加密的实现指南,并详细介绍我们所做的一些技术选择。

我们考虑了一个完整的JavaScript环境,因为它可以在浏览器中本地执行,也可以通过Cordova等框架在移动环境中执行,或者使用Electron在桌面中执行。

我们依赖WebCrypto API规范,因为它是W3C推荐的标准,已经过社区审核,并通过SubtleCrypto接口得到大多数现代浏览器的本地支持。

尽管此API是最新的,但它主要用于:

ℹ️ WebCrypto API可用于浏览器和移动设备(例如Cordova),我们对其进行了测试。然而,桌面环境需要Node.js Javascript,它没有实现SubtleCrypto接口。本机支持一种替代方案,可以使用polyfill版本,尽管它是实验性的,目前还不推荐使用。

在下文中,术语generate、derival、wrap、unwrap、encrypt、decrypt指代它们的等价实现。

使用的对称加密算法是AES-GCM,它允许:

  • 稳健的加密
  • 数据完整性,得益于Gallois消息验证码(GMAC)
  • 附加任意明文元数据

用于存储加密密钥的加密是AES-KW:它是专门为这项任务设计的,称为包装(反向展开),并允许像AES-GCM一样确保加密的完整性。

AES-KW的一个好处是,iv不需要产生非确定性加密,因为它在算法规范中进行内部处理。

ℹ️ 如果没有特别提及,性能测量是在Thinkpad T480上进行的,该T480配有i7-8550U CPU、16Go RAM和SSD。浏览器是Mozilla Firefox 70.0。

每个给定的度量都是1000次相同计算的平均值。

导出密钥

要从密码和salt(例如Km)派生强密钥,我们使用具有以下参数的SubtleCrypto.deriveKey():

  • algorithm;;指定派生算法的对象,这里是具有以下属性的Pbkdf2Params:
    • name = PBKDF2
    • salt = email
    • iterations = 100 000
    • hash = SHA-256
  • baseKey=P:派生输入,这里是用户密码
  • derivedKeyAlgorithm={name:“AES-KW”}:派生密钥的加密算法
  • extractable=false;表示以后不会导出密钥
  • keyUsages=[“wrapKey”,“unwrapKey“];此密钥的授权操作。

性能

关键推导性能与迭代次数呈线性关系,如图所示:

key-derivation

关键衍生性能

有关更精确的值,请参见下表:

ITERATIONS 1 000 10 000 100 000 1 000 000
Time (ms) 3 25 253 2398

迭代次数对安全性至关重要:越高越好,因为它会迫使攻击者执行更多操作,从而减缓攻击。

100000次迭代似乎是安全性和性能之间的一个很好的折衷方案。同样不应该忘记的是,我们在现代计算机上进行了测试,而一些用户可能拥有较旧的硬件,导致性能下降,这可能会阻碍用户体验。

有关迭代选择的更多见解,请参阅本文。

密钥生成

为了生成对称密钥,例如Kvault、Kaes-i,我们使用具有以下参数的SubtleCrypto.generateKey():

  • algorithm = {name: "AES-GCM", length: 256}; the encryption algorithm and the key length
  • extractable = true ; indicates that the key will be later exported
  • keyUsages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"] ; the authorized operations for this key. Typically, a Kaes-i will have ["encrypt", "decrypt"] while Kvault will be used to wrap/unwrap Kaes-i, thus ["wrapKey", "unwrapKey"]

性能

密钥生成操作以及包装和展开在性能级别上并不重要,如下所示:

key-operations-performances

操作不超过1.2毫秒,这低于人类的感知。

密钥包装

要包装加密密钥,即以指定的格式加密并序列化它,我们使用具有以下参数的SubtleCrypto.wrappKey():

  • format = "raw" ; the exported format
  • key ; the key to export, e.g. Kaes-i
  • wrappingKey ; the export key, e.g. Kvault
  • wrapAlgo = "AES-KW" ; the encryption wrapping algorithm

密钥展开

要打开包装的密钥,即按指定格式解密和反序列化它,我们使用SubtleCrypto.unwrapKey()和以下参数:

  • format = "raw" ; the expected key format
  • wrappedKey ; the encrypted key, e.g. Kaes-i
  • unwrappingKey ; the key used to wrap, e.g. Kvault
  • wrapAlgo = "AES-KW" ; the encryption wrapping algorithm
  • unwrappedKeyAlgo = {name: "AES-GCM", length: 256} ; the expected imported key format. If the wrappedKey is Kvault, it will be {name: "AES-KW"}
  • extractable = true ; the key can be re-exported later
  • keyUsages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"] ; the authorized operations on the imported key. Typically, a Kaes-i will have ["encrypt", "decrypt"] while Kvault will be used to wrap/unwrap Kaes-i, thus ["wrapKey", "unwrapKey"]

数据解密

要解密数据,我们使用具有以下参数的SubtleCrypto.decrypt():

  • 算法;指定要解密的算法的对象。我们使用具有以下属性的AesGcmParams:
    • name=“AES-GCM”;加密算法
    • iv;在加密时随机选择的初始化矢量。它应该与加密数据一起检索。对于AES-GCM,建议使用96位iv。参见NIST建议。
    • tagLength=128;预期GMAC长度。有关GMAC长度的见解,请参阅NIST的建议。
  • 钥匙加密密钥
  • 数据要解密的数据

ℹ️ 数据必须表示为BufferSource对象。

性能

解密的性能与加密大致相同,将在下一节中讨论。

数据加密

要加密数据,我们使用具有以下参数的SubtleCrypto.encrypt():

  • 算法;指定要加密的算法的对象。我们使用具有以下属性的AesGcmParams:
    • name=“AES-GCM”;加密类型
    • iv;在加密时随机生成的初始化矢量。它应该与加密数据一起存储。对于AES-GCM,建议使用96位iv。参见NIST建议。
    • tagLength=128;GMAC长度。有关GMAC长度的见解,请参阅NIST的建议。
  • 钥匙加密密钥
  • 数据要加密的数据

ℹ️ 数据必须表示为BufferSource对象。

加密性能

此外,我们还执行了数据加密的基准测试。为此,我们在Cozy Drive中实现了加密方法,这是一款纯客户端文件管理应用程序,用JavaScript和React编写,可以在浏览器和移动环境中运行,通过Cordova包装器,使用WebView。我们的实现使用WebCrypto API和上面描述的方法和参数。

我们关注的是文件加密,因为从用户的角度来看,它可能是最常见的数据类型。然而,任何类型的数据都可以与此实现一起使用,因为加密模块作为web模块与应用程序逻辑分离。所有代码都是开源的,可以在Github上获得。

除了加密成本本身,我们还评估了读取成本,因为这是加密文件的必要步骤。

我们在以下环境中进行了测试:

Desktop web browser (Firefox 70.0)

  • Thinkpad T480 (i7-8550U CPU, 16Go RAM)

Mobile app

  • iPhone 11 -iOS 13.3 (simulator)
  • MacBook Pro (2.3 GHz i5 CPU, 16Go RAM)
  • Webview: UIWebView
  • iPhone X - iOS 13.3

Webview: UIWebView

  • Xiaomi Mi 9 - Android 9
    • Webview: Chrome 80.0

ℹ️ 所有Y轴均为对数刻度。

Firefox 70.0

firefox-70.

这表示在笔记本电脑上的Firefox浏览器中采取的措施。

正如我们所看到的,加密成本总是低于读取时间,并且只要文件大小较小,加密成本就相当低。

然而,我们可以注意到成本从1MB开始加速。在这个限制之前,加密成本几乎是免费的,不到20毫秒,10 MB的加密成本会跳到100毫秒以上。

有趣的是,这种加速似乎与FileReader API的文件块大小一致:然后我们可以假设这种开销可能是由将文件拆分为较小的块引起的。

然而,尽管有这种加速,成本与文件大小呈次线性关系。这是个好消息,但对于大文件来说仍然会带来巨大的成本:1 GB的文件上传需要大约10秒的读取时间和大约9秒的加密时间,因此总共需要将近20秒。

现在,让我们看看手机上的表演。

iOS 13.3 - Simulator iPhone 11

ios13.3

我们在苹果公司提供的iPhone 11模拟器中进行了这项测试。我们可以看到整体性能比在浏览器中要好。同样,当文件大于1MB时,成本往往会增加,尤其是对于加密。读取操作相对稳定,最高可达10MB。

然而,使用模拟器可能会对这种评估产生偏差,因为模拟器可能无法准确模拟移动硬件,尤其是CPU。因此,我们也在实际设备中进行了测量。

iOS 13.3-iPhone X

iphoneX

表演的形状实际上看起来与模拟器非常相似。请注意,对于1GB的文件没有度量标准,因为设备需要太多的内存来处理。设计处理大文件的策略可能很有趣,比如将文件分成块并分别加密每个部分,或者执行加密流。有关更多见解,请参阅下一节。

安卓9-小米小米9

android9

在安卓设备上,整体性能有点落后于iPhone,尤其是在读取方面,这可能是硬件差异造成的。

然而,值得注意的是,从1K到1MB的加密成本几乎相同。加速度为10 MB。

性能by 设备

在这里,我们将所有设备的性能分组,以强调环境差异。

devices.

environment

令人惊讶的是,与移动环境相比,Firefox桌面在读取操作方面表现不佳。我们还注意到,iOS在小文件上表现得很好,但所有环境在大文件上都能达到类似的性能,尤其是在加密方面。

性能调查结果

性能基准测试强调了这样一个事实:对于高达1MB的数据,加密成本几乎是微不足道的。因此,只要数据大小保持合理,客户端加密现在是现实的,即使在浏览器中也是如此。

随着文件大小的增长,加密的执行成本往往与读取操作相同,而读取操作对于大文件来说可能是相当大的。然后,有必要研究新的策略,以在不降低用户体验的情况下有效地应对这种成本。

Web workers

在我们的实现中,我们探索了使用网络工作者的可能性。这项最新技术在现代浏览器中可用,提供了在后台线程中运行任务的可能性。这对于会阻塞主线程并为用户提供冻结界面的计算量大的任务特别有用。

我们在一个网络工作者中实现了加密,对任务本身没有影响。然而,实际执行工人需要增加额外的成本。

同样值得注意的是,web工作者不共享内存,如文档中所述:

主页面和辅助进程之间传递的数据是复制的,而不是共享的。对象在交给工作者时进行序列化,然后在另一端进行反序列化。页面和辅助进程不共享同一个实例,因此最终结果是在每一端创建一个重复实例。大多数浏览器将此功能实现为结构化克隆。

因此,应该在web worker中执行整个数据上传,而不是读取主线程中的数据,将数据复制到worker并执行加密,这对于大文件来说可能非常消耗内存。

一个很好的实现例子是Firefox Send。

文件流

WebCrypto API仅允许通过块进行加密/解密;这意味着在执行操作之前必须完全加载数据。

在出现巨大文件的情况下,流式传输数据会更有效,以避免必须将数据完全加载到内存中一次,这可能会导致内存故障,就像我们在移动设备上的测试中所经历的那样。

遗憾的是,目前WebCrypto API还不支持此功能。关于这一问题已经公开,在本文件的编辑过程中仍在讨论。

请注意,仍然可以手动实现此流媒体,就像Mozilla为其发送服务所做的那样,但这需要额外的工作。

结论和观点

通过消息应用程序、电子邮件服务、密码管理器、文件存储等,客户端加密逐渐成为主流。

然而,尽管它对用户隐私有明显的好处,但在很大程度上仍然没有得到充分利用。

一个常见的批评是性能的影响,正如我们在本文档中所示,只要数据大小保持合理,性能就会保持相对较低。网络工作者和文件分割似乎都是降低成本的好选择,而且并不相互排斥。

此外,WebCrypto API的兴起大大减轻了开发人员的任务,提供了一个简单的API来加密/解密数据。然而,这个API的实际使用并不能直接做出正确的选择。我们希望本文档能为任何有兴趣实现客户端加密和身份验证的人提供全面的见解,同时还要记住加密决不能掉以轻心。引用自WebCrypto主页:

如果你不确定自己在做什么,你可能不应该使用这个API。

在客户端加密领域仍有许多挑战需要解决:我们在下面列出了其中一些挑战,并展望了未来。

改进的身份验证安全性

我们的身份验证方法的主要缺点是必须将从密码派生的哈希传输到服务器端。尽管据说它在密码上什么都没有透露,但由于强大的硬件和字典攻击,它仍然可以被窃取,稍后被破解。

SRP协议是一种零知识协议,它不需要从密码中获取秘密,也不会向被破坏的服务器或能够破坏TLS连接并执行中间人攻击的攻击者透露任何信息。该协议声称由1Password和ProtonMail使用,但比上述身份验证方案更复杂,也可以说更慢。

ℹ️ Mozilla有一个开源的Javascript实现,声称在其身份协议的生产中使用。请参见节点srp。

不可靠服务器

在web上下文中,服务器动态地传递由浏览器运行的脚本。然后,服务器被认为是可靠的,可以传递正确的代码。

然而,正如ProtonMail的安全分析中所提到的,欺骗性服务器可能会提供损坏的脚本来拦截用户密码并能够解密其数据。

我们在威胁模型中没有考虑这种攻击,因为它超出了“诚实但好奇”的假设,但我们提到它是为了彻底。

解决这个问题的一种方法是使用SRI安全功能,该功能在浏览器中可用,现在由ProtonMail使用:提供HTML的服务器必须提供脚本的哈希,该哈希将由浏览器计算以确保其完整性。如果值不匹配,则可能表明服务器没有提供预期的资源:因此脚本被阻止。

然而,如果传递脚本的服务器与传递HTML的服务器相同,这是不够的:然后散列可能是损坏的Javascript中的一个。

但是,如果服务提供商以开源的方式发布带有预期哈希的脚本,任何人都可以检查服务器是否提供了预期的代码。虽然这并不令人满意,因为它需要用户手动操作,但它对服务器提供的内容添加了一些控制。

服务器端计算

进行客户端加密时的一个严重缺点是服务器端计算能力的丧失。由于数据被加密,服务器无法对其进行处理,如索引、人工智能计算、搜索等。

没有通用的解决方案来克服这个依赖于许多变量的问题,并且需要在加密表面、性能、协议复杂性等方面找到折衷方案。

例如,可以保持索引数据的清晰,例如文件层次结构、创建日期等,但代价可能会削弱用户隐私。

使用PouchDB这样的浏览器数据库,也可以在客户端加密索引和执行查询,但这是以性能和可扩展性为代价的。

另一种方法包括以确定性的方式加密客户端上的数据,以便可以对加密的术语(例如目录ID)进行索引和检索。这里的缺点是基于频率的攻击的风险,攻击者会观察查询的时间和结果来推断信息。

更复杂的解决方案涉及同态加密,它允许直接对加密数据进行处理,而不需要随时解密。这仍然是一个活跃的研究主题,但目前看来,计算量太大,上下文太特殊,无法成为一个实用的解决方案:在最佳情况下,AES128块需要大约4分钟才能进行评估,任何同态处理都需要特定而复杂的设计,必须仔细分析。

用户密码丢失

在所提出的加密方案中,安全性的根源是用户密码。因此,如果用户丢失了密码,就无法恢复加密的数据,因为服务器永远不会知道加密密钥。这是面向安全的产品(如密码管理器)所承担的风险,但在其他情况下这可能是不可接受的。

在密码丢失后恢复加密数据的一个优雅的解决方案是使用Shamir的秘密共享。其原理如下:

  • 用户选择一定数量的可信收件人,例如5个,以及法定人数,例如3个。
  • 用户密钥,这里是主密钥,被拆分为与受信任的收件人一样多的共享。
  • 用户通过安全通道将共享分发给受信任的收件人。

如果用户丢失了密码,她会联系她信任的收件人以获得他们各自的共享。她只需要取回与法定人数相等的股份就可以收回秘密。

虽然很简单,但该协议提出了许多问题,特别是用户体验、接收者的发现、授予接收者的信任、共享的可持续性等。

本文地址
https://architect.pub/end-end-encryption-how-encrypt-data-web-application
SEO Title
End-to-end encryption: how to encrypt data in a web application