哪种策略可以加密多个用户访问的数据?

信息安全 加密 密码学
2021-08-16 13:06:26

我需要建议在加密的特定点上设计我的数据库架构(在 Web 应用程序的上下文中);知道必须尊重以下要素:

1-数据必须在数据库中安全加密

这是为了防止攻击者,主要是为了让用户知道即使是员工也无法访问他们的数据,因此技术团队不能访问密钥。

2-数据仅限于用户帐户

(意思是:每个用户都有自己的一组数据,与他们的用户 ID 相关联)

所以我想用用户的密码作为加密密钥,但这会带来一个问题:当数据的所有者决定更改密码时,数据必须重新加密,这对服务器功率的要求过高。

3-加密数据的所有者必须能够将其数据的访问权限授予其他用户

(意思是:有一个邀请系统,一个用户的部分或全部数据可以被其他被邀请的用户访问)

这使得不可能使用用户的密码来加密数据,因为我们不想共享我们的密码。

所以我想到了私钥/公钥加密,但私钥必须存储在某个地方。将其存储在数据库中只会使整个加密变得无用;并将其存储在客户端也是不可能的,因为它会限制从安装了私钥的唯一计算机对应用程序的访问。

4-其他用户可以从此给定的访问权限中撤消

这意味着,如果我们考虑私钥/公钥解决方案,我们必须能够删除提供给被撤销用户的私钥。

任何关于如何构建这样一个系统的建议,或者我能得到灵感的任何想法都非常受欢迎。谢谢


更新

似乎到目前为止,最好的方法是使用非对称密钥(我称之为data-key)加密数据,然后使用对称密钥(这是用户的密码)加密数据密钥的私有部分.

这似乎是一个很好的解决方案;但是我能想到几个问题:

  • 当用户登录时,他的明文密码必须在会话打开时存储在服务器端的内存中,因为我们需要为每个请求解密数据。这是一个安全漏洞,因为黑客可以访问所有打开的会话,并且他们的用户密码以明文形式存储。

  • 当数据被共享时(即所有者向受邀者授予访问权),数据密钥使用所有者的明文密码进行解密,然后使用受邀者的明文密码进行加密。问题是所有者和被邀请者不需要同时登录,因此服务器在邀请完成时不会知道被邀请者的明文密码,并且无法加密数据-钥匙。

  • 当用户丢失密码并请求生成新密码时,他将丢失所有无法再解密的数据

4个回答

TL;DR:生成一个数据密钥对,用所有具有写访问权限的用户的公钥加密私有部分,用所有具有读访问权限的用户的公钥加密公共部分。


让我们一一解决:

  1. 数据必须在数据库中安全加密

这是为了防止攻击者,主要是为了让用户知道即使是员工也无法访问他们的数据,因此技术团队不能访问密钥。

鉴于此要求,您需要考虑的最重要的属性是服务器在任何情况下都无法获取加密或解密数据所需的信息。这意味着所有加密/解密都必须发生在客户端由于服务器能够按需注入 JavaScript 代码,因此当您需要进行端到端加密时,基于 Web 的系统本质上是不安全的;更注重安全的用户会希望控制用于访问服务的客户端软件,因此他们希望将其实现为桌面应用程序。

  1. 数据范围仅限于用户帐户
  2. 加密数据的所有者必须能够将其数据的访问权限授予其他用户

这两个限制意味着多个用户需要能够解密数据。这意味着解密数据的秘密需要与其他用户共享。

  1. 其他用户可以从这个给定的访问权限中撤消

这意味着,如果我们考虑私钥/公钥解决方案,我们必须能够删除提供给被撤销用户的私钥。

要撤消访问权限,您需要使用新密钥重新加密数据。正如其他答案所讨论的那样,您不能强制健忘。

描述这一点的最佳方式可能是举例。


注释:

  • P(x) 是名为 x 的私钥。
  • Q(x) 是 x 的匹配公钥。
  • e = E(d, Q(x))手段是用公钥e加密明文的结果dx
  • d = D(e, P(x))手段是用私钥d解密密文的结果ex

假设 Alice 想要与 Bob、Charlie 和 Dave 共享数据。Alice 希望让 Bob 能够读取和写入数据,Charlie 可以读取数据但不能生成有效数据,而 Dave 只能写入但不能解密其他人写入的内容(本质上它是 Dave 的放置文件夹)。

所有用户都有用户密钥对。P(Alice),Q(Alice)是 Alice 的用户密钥对;P(Bob),Q(Bob)是 Bob 的用户密钥对;P(Charlie),Q(Charlie)是 Charlie 的用户密钥;P(Dave),Q(Dave)是 Dave 的用户密钥对。

该系统有一个用户密钥注册表,用户可以在其中共享其用户密钥的公共部分。用户如何安全地检索和验证另一个用户的用户密钥超出了此答案的范围,留给读者作为练习。大多数用户可能只是相信您在服务器上设置的访问限制,但更具安全意识的用户需要做一些类似于 GPG 密钥签名方的事情;。

所有用户都应将其用户密钥的私有部分保密。如何详细执行此操作超出了此答案的范围,但您绝对不想将私有用户密钥存储在未加密的服务器中。相反,我建议可以使用从用户密码和盐派生的对称密钥加密用户密钥,然后将加密的用户密钥和盐存储在服务器上。

为了安全地存储数据“Hello World”,Alice 首先生成一个数据密钥对:P(data), Q(data). Alice 然后使用数据密钥公钥加密数据:

plaintext = "Hello World"
ciphertext = E(plaintext, Q(data))

鉴于公钥密码学的特性,我们知道它ciphertext只能由知道的人解密P(data)(请注意,数据密钥的私有和公共概念只是一个约定问题,两者都P(data)必须Q(data)对不需要它们的每个人保密,例如服务器)

爱丽丝希望让鲍勃和查理能够读取这些数据,所以爱丽丝检索鲍勃和查理的公钥Q(Bob)并用它们进行Q(Charlie)加密P(data),另外为了让爱丽丝在未来解密文件,可能来自不同的机器,爱丽丝做使用她自己的公钥进行相同的操作:

alice_read_key = E(P(data), Q(Alice))
bob_read_key = E(P(data), Q(Bob))
charlie_read_key = E(P(data), Q(Charlie))

Alice 希望让 Bob 和 Dave 能够写入 Alice、Bob 和 Charlie 可以读取的数据。Alice 还希望将来能够更新数据。为了能够做到这一点,AliceQ(data)使用Q(Alice)Q(Bob)和加密公共数据密钥Q(Dave)

alice_write_key = E(Q(data), Q(Alice))
bob_write_key = E(Q(data), Q(Bob))
charlie_write_key = E(Q(data), Q(Charlie))

Alice 然后将所有encrypted_key, alice_read_key, bob_read_key, charlie_read_key, alice_write_key, bob_write_key, 和charlie_write_key发送到服务器。

由于服务器/攻击者永远不会拥有P(data)orQ(data)并且由于服务器也没有用于解密任何 的私钥read_keys,因此服务器将无法解密ciphertext

当查理想要检索数据时,他需要下载ciphertextcharlie_read_keycharlie_read_key用他的私人用户密钥解密以获得P(data)然后使用P(data)解密ciphertext

P(data) = D(charlie_read_key, P(Charlie))
plaintext = D(ciphertext, P(data))

现在查理拥有plaintext. 然而,由于查理没有写密钥,他没有Q(data),因此他将无法以其他人能够成功解密的方式更新系统中的数据。

接下来,Dave 需要能够添加到数据中。他无法读取,ciphertext但他可以通过解密他的写密钥来附加到它以获得 Q(数据):

new_plaintext = "New Data"
Q(data) = D(dave_write_key, P(Dave))
new_ciphertext = E(new_plaintext, Q(data))
updated_ciphertext = ciphertext + new_ciphertext

现在 Dave 可以将 updated_ciphertext 发送到服务器。

(请注意,在大多数非对称加密算法中,您不能简单地连接两个密文并期望能够对其进行解密,因此您可能需要存储一些元数据,以将密文块分开并分别解密)

这给我们留下的只有撤销。要撤销访问权限,您至少P(data)需要解密ciphertextplaintext,生成新的数据密钥对:P'(data)Q'(data),并使用新的数据密钥对重新加密明文:

plaintext = D(ciphertext, P(data))
new_ciphertext = E(plaintext, Q'(data))

然后你需要更新每个人的写密钥和读密钥。

要将新用户添加到现有文件中,您只需创建他们的写密钥和读密钥。只有自己可以解密其读密钥的人才能将读密钥扩展给新用户,只有自己可以解密其写密钥的人才能将写密钥扩展给新用户。


如果不需要本系统的细粒度权限权限,(IOW,如果所有能读取数据的用户也可以更新);或者如果您使用其他方式来强制执行细粒度的权限,那么您可以用对称数据密钥替换非对称数据密钥(琐事:具有对称数据密钥的系统类似于多收件人 PGP 加密的电子邮件有效;因此您可能需要对此进行调查)。

这类问题的通用方法是知识推理和间接推理。

你希望每个用户都能做一些其他用户或“技术人员”不能做的事情;因此,每个用户都必须知道其他人不知道的秘密值。用户的密码可以是这样的秘密;否则,您将需要存储在客户端的内容。

对每个数据元素的访问必须在任何时候都只能由一组选定的人访问,因此必须对数据进行加密,并且这些人确切知道加密密钥。此外,您希望能够在每个元素的基础上共享元素,因此每个元素(文件)都需要有自己的加密密钥。

你不能强迫健忘;如果有人在某个时候知道某个文件的内容,那么您就不能让它忘记它。实际上,他们可能已经在自己的机器上进行了备份。因此,您不能撤销对数据元素的访问。充其量,您可以基于每个文件选择可以阅读它的人,因此不会向某些人提供任何给定文件的新版本。

由于您希望用户相互授予对某些文件的访问权限,因此您需要某种形式的集合点,这将通过非对称加密最容易实现。


这导致了以下设计:

  • 每个用户U拥有一个适用于非对称加密(例如 RSA)的公钥/私钥对P U / S U 。

  • 私钥存储在“某处”,只有合法的所有者才能访问它。一种方法是使用用户密码加密私钥(假设用户从不将他的密码发送到您的服务器,否则“技术人员”可以获取它)。或者,用户的私钥存储在他的台式机/笔记本电脑系统上的文件中。

  • 每个数据元素(或文件)都使用其自己的随机生成的密钥K(对称加密)进行加密。

  • 与每个文件一起存储K的加密版本以及应该能够读取该文件的用户的公钥。如果用户U是该集合的一部分,则该用户使用他的私钥S U来恢复K并解密文件。

  • 与另一个用户V共享文件是通过恢复K来完成的,然后用P V (用户V的公钥)加密K并将结果存储在文件中(或通过其他机制使其对用户V可用)。

  • 如果用户更改了他的密码,那么这最多会影响他的私钥的存储。与文件无关。虽然用户的密码可能会更改,但他的公钥/私钥对是永久的。

  • 当文件被修改时,您可以将新版本视为一个新的独立文件,具有自己的新密钥K和自己的一组收件人。如果新的接收者集与旧集(或其超集)相同,那么您可以简单地重用相同的密钥K,这对于实现可能更简单。更改密钥K与“撤销访问”最相似(受不可执行的健忘警告)。


当然,“技术人员”仍然控制执行这些操作的任何软件(特别是在 Web 环境中,Javascript 由服务器本身发送,或者如果加密/解密操作在服务器端完成),因此,如果他们真的想欺骗用户,那么就必须假设他们可以。

这是一个有趣的问题,但实际上已经在各种开源应用程序中得到了解决。对于您的用例,我建议借鉴 ownCloud 的加密模型(具有开源的优势)。

此模型在您的软件上的一般应用如下所示:

1)当然这可以通过多种方式完成,但我建议让应用程序服务器本身使用非对称(公钥-私钥)加密然后对称加密来加密这些数据。对称加密可以做很多事情——比如将一半的密钥放在服务器上,并要求用户提供另一半,等等来解决这个问题。

2)正如o11c指出的那样,用对称加密方法(密码)加密非对称私钥肯定会解决这个问题。

3)当其他用户需要数据的副本时,您必须让应用服务器解密,然后为该用户重新加密数据。这样,您最终会为每个需要它的用户复制数据。ownCloud 方法很有趣——它使用非对称“共享密钥”来加密用户共享的文件。该共享密钥是为每个文件和共享文件的用户生成的。然后,您可以让应用程序服务器解密数据,使用该用户的公钥对其进行加密,然后只有该用户的密码才能解锁解密文件所需的私钥。

4) 在 3 上,您需要做的就是删除新生成的共享密钥并安全地撤销访问权限(前提是他们没有执行诸如下载或执行屏幕截图等操作)。

Apple 在 iCloud 上使用了这种机制。我相信这就是它的工作原理(如果我没记错的话),并且与其他人的建议略有不同。据我了解,它只涉及非对称加密。

1) 设备(iPhone、iPad 等)生成密钥对(设备密钥)。

2) 对于新的 iCloud 帐户,设备会生成第二个密钥对(加密密钥)。

3) 设备使用公共设备密钥对加密密钥的私有部分进行加密。(明文)公共加密密钥和(加密)私有加密密钥都存储在服务器上。

4) 设备使用公共加密密钥对发送到服务器的数据进行加密。

共享数据:

1)您需要一台已经连接到云端的设备。我们称该设备为 1。新设备为设备 2。2) 设备 2 生成自己的设备密钥对。3) 设备 2 将其公钥发送给设备 1(直接或通过云。直接更安全)。4) 设备 1 使用自己的私钥解密加密私钥,然后使用设备 2 的公钥对其进行加密。

第 3 步可能存在漏洞;如果攻击者可以欺骗设备 1 接受他的公钥,他可能会访问共享数据。我不知道这是如何解决的,但可能涉及设备识别和密钥指纹。

编辑澄清:我的描述中的加密密钥对将是每个用户的,但您可以在不同的范围内使用相同的机制。范围决定了“共享单位”——如果您希望能够决定共享或不共享单个文件,那么每个文件都需要有自己的密钥对。对于共享,只会复制密钥对,而不是基础数据。