数据库

Vault

在 Postgres 中管理密钥。


Vault 是一个 Postgres 扩展程序和配套的 Supabase UI,可以安全且轻松地将加密密钥和其他数据存储在数据库中。这为使用 Postgres 的方式打开了许多可能性,超越了标准发行版的功能。

在底层,Vault 是一个使用 认证加密 在磁盘上存储的密钥表。然后,它们可以通过 Postgres 视图以解密的形式提供,以便应用程序可以从 SQL 中使用这些密钥。由于密钥以加密和认证的形式存储在磁盘上,因此所有备份或复制流也以无法解密或伪造的方式保留此加密。

Supabase 为 Vault 提供了一个仪表板 UI,使存储密钥变得容易。单击一个按钮,输入您的密钥,然后保存。

您可以使用 Vault 存储密钥 - 从环境变量到 API 密钥,一切皆可。然后,您可以在数据库中的任何地方使用这些密钥:Postgres 函数、触发器和 Webhooks。从 SQL 的角度来看,访问密钥就像查询一个表(或者在这种情况下,一个视图)一样简单。底层的密钥表将以加密形式存储。

使用 Vault#

您可以从 UI 或使用 SQL 管理密钥。

添加密钥#

还有一个方便的函数可以创建密钥,名为 vault.create_secret()

1
select vault.create_secret('my_s3kre3t');

该函数返回新密钥的 UUID。

显示结果
1
-[ RECORD 1 ]-+-------------------------------------
2
create_secret | c9b00867-ca8b-44fc-a81d-d20b8169be17

密钥还可以具有可选的唯一名称和可选的描述。这些也是 vault.create_secret() 的参数

1
select vault.create_secret('another_s3kre3t', 'unique_name', 'This is the description');
显示结果
1
-[ RECORD 1 ]-----------------------------------------------------------------
2
id | 7095d222-efe5-4cd5-b5c6-5755b451e223
3
name | unique_name
4
description | This is the description
5
secret | 3mMeOcoG84a5F2uOfy2ugWYDp9sdxvCTmi6kTeT97bvA8rCEsG5DWWZtTU8VVeE=
6
key_id |
7
nonce | \x9f2d60954ba5eb566445736e0760b0e3
8
created_at | 2022-12-14 02:34:23.85159+00
9
updated_at | 2022-12-14 02:34:23.85159+00

查看密钥#

如果您查看 vault.secrets 表,您会看到您的数据以加密形式存储。要解密数据,有一个自动创建的视图 vault.decrypted_secrets。此视图将在运行时解密密钥数据

1
select *
2
from vault.decrypted_secrets
3
order by created_at desc
4
limit 3;
显示结果
1
-[ RECORD 1 ]----+-----------------------------------------------------------------
2
id | 7095d222-efe5-4cd5-b5c6-5755b451e223
3
name | unique_name
4
description | This is the description
5
secret | 3mMeOcoG84a5F2uOfy2ugWYDp9sdxvCTmi6kTeT97bvA8rCEsG5DWWZtTU8VVeE=
6
decrypted_secret | another_s3kre3t
7
key_id |
8
nonce | \x9f2d60954ba5eb566445736e0760b0e3
9
created_at | 2022-12-14 02:34:23.85159+00
10
updated_at | 2022-12-14 02:34:23.85159+00
11
-[ RECORD 2 ]----+-----------------------------------------------------------------
12
id | c9b00867-ca8b-44fc-a81d-d20b8169be17
13
name |
14
description |
15
secret | a1CE4vXwQ53+N9bllJj1D7fasm59ykohjb7K90PPsRFUd9IbBdxIGZNoSQLIXl4=
16
decrypted_secret | another_s3kre3t
17
key_id |
18
nonce | \x1d3b2761548c4efb2d29ca11d44aa22f
19
created_at | 2022-12-14 02:32:50.58921+00
20
updated_at | 2022-12-14 02:32:50.58921+00
21
-[ RECORD 3 ]----+-----------------------------------------------------------------
22
id | d91596b8-1047-446c-b9c0-66d98af6d001
23
name |
24
description |
25
secret | S02eXS9BBY+kE3r621IS8beAytEEtj+dDHjs9/0AoMy7HTbog+ylxcS22A==
26
decrypted_secret | s3kre3t_k3y
27
key_id |
28
nonce | \x3aa2e92f9808e496aa4163a59304b895
29
created_at | 2022-12-14 02:29:21.3625+00
30
updated_at | 2022-12-14 02:29:21.3625+00

请注意,此视图有一个 decrypted_secret 列,其中包含解密的密钥。视图不会存储在磁盘上,它们仅在查询时运行,因此密钥在磁盘上以及任何备份转储或复制流中都保持加密状态。

您应始终确保使用适当的 SQL 权限设置来保护对此视图的访问,因为任何访问该视图的人都可以访问解密的密钥。

更新密钥#

可以使用 vault.update_secret() 函数更新密钥,此函数使更新密钥变得容易,只需提供密钥 UUID 作为第一个参数,然后提供更新后的密钥、更新后的可选唯一名称或更新后的描述

1
select
2
vault.update_secret(
3
'7095d222-efe5-4cd5-b5c6-5755b451e223',
4
'n3w_upd@ted_s3kret',
5
'updated_unique_name',
6
'This is the updated description'
7
);
显示结果
1
-[ RECORD 1 ]-+-
2
update_secret |
3
4
postgres=> select * from vault.decrypted_secrets where id = '7095d222-efe5-4cd5-b5c6-5755b451e223';
5
-[ RECORD 1 ]----+---------------------------------------------------------------------
6
id | 7095d222-efe5-4cd5-b5c6-5755b451e223
7
name | updated_unique_name
8
description | This is the updated description
9
secret | lhb3HBFxF+qJzp/HHCwhjl4QFb5dYDsIQEm35DaZQOovdkgp2iy6UMufTKJGH4ThMrU=
10
decrypted_secret | n3w_upd@ted_s3kret
11
key_id |
12
nonce | \x9f2d60954ba5eb566445736e0760b0e3
13
created_at | 2022-12-14 02:34:23.85159+00
14
updated_at | 2022-12-14 02:51:13.938396+00

深入了解#

如我们所提到的,Vault 使用透明列加密 (TCE) 以认证加密的形式存储密钥。您可能对其中一些细节感到好奇。认证是什么意思?加密密钥存储在哪里?本节将解释这些细节。

带有关联数据的认证加密#

TCE 的第一个重要特性是它使用基于 libsodium带有关联数据的认证加密 算法。

加密密钥位置#

认证加密意味着除了数据被加密之外,它也被签名,因此无法被伪造。您可以保证数据是由您信任的人加密的,而单独加密则无法保证这一点。解密函数在解密值之前会验证签名是否有效。

关联数据意味着您可以将同一行中的任何其他列包含在签名计算中。这不会加密这些其他列 - 而是确保您的加密值仅与该行的列相关联。如果攻击者将加密值从另一行复制到当前行,签名将被拒绝(假设您在关联数据中使用了唯一的列)。

另一个重要特性是加密密钥从不与加密数据一起存储在数据库中。即使攻击者可以捕获整个数据库的转储,他们只会看到加密的数据,永远不会看到加密密钥本身

这是一个重要的安全预防措施 - 将加密密钥存储在数据库本身中价值很小,这就像锁上您的前门,但把钥匙留在锁里!将密钥存储在数据库外部可以解决此问题。

密钥存储在哪里?Supabase 在我们安全的后端系统中创建和管理加密密钥。我们安全地将此密钥与您的数据分开保存。您仍然可以控制您的密钥 - 提供了一个单独的 API 端点,您可以使用它来访问密钥,如果您想在 Supabase 外部解密您的数据,可以使用它。

应仔细考虑哪些角色应该具有对 vault.secrets 表的访问权限。授予访问权限的两种方法是,首先,postgres 用户可以显式授予对 vault 表本身的访问权限。

资源#