是否可以在 JSONB 键值上使用 pgp_sym_encrypt?

Is it possible to use pgp_sym_encrypt on JSONB Key value?

我到处寻找,试图找到这个问题的答案,但我无法找到答案。

主要问题,您能否在 JSON 数组列上使用 pgp_sym_encrypt。例如,假设我有一个表单 post 由 req.body 作为

返回
[{
id: 22,
fname: "jim", 
lname: "smith",
email: "someemail@email.com"
}]

现在,我想将其作为 JSONB 存储在 postgres 中,但是假设我想使用 pgp_sym_encrypt 加密电子邮件地址,是否可以这样做?

我们在常规列上使用了 pgp_sym_encrypt,但我们正在研究 JSONB 以可能将数据存储为 JSON,但有时我们可能需要加密部分数据JSON 表示 PII 的对象,但是仍然希望能够使用 pgp_sym_decrypt

在该字段上进行搜索

我不确定我们的想法是否得到支持,或者它可能是一个糟糕的用例,因为我们似乎找不到专门针对此用例定制的任何东西。我们已经在 SO 上看到了一些 post,但它们并没有真正涉及如何在 JSONB 列类型上执行此操作,或者如果可能的话。

我们不希望加密整个对象,只是其中的一部分,但是当提取数据时,比如通过 API 我们希望解密值,主要只是希望它在静态时被加密在数据库中

这确实是一个有趣的问题。

我已经对我的本地 PostgreSQL 13.1 安装进行了一些测试,并且可以正常工作:

  1. 创建一些示例数据:
create table test_jsonb_crypto (id serial primary key, jsonb_col jsonb);
insert into test_jsonb_crypto (jsonb_col) VALUES('{"data1": {"data2": "test"}}');
 id |           jsonb_col            
----+--------------------------------
  1 | {"data1": {"data2": "test"}}

  1. 加密一个值:
update test_jsonb_crypto set jsonb_col = jsonb_set(jsonb_col, '{"data1", "data2"}', ('"'||encode(pgp_sym_encrypt(jsonb_col->'data1'->>'data2', 'pwd'), 'hex')::varchar||'"')::jsonb) WHERE id = 1;
select * from test_jsonb_crypto;
id |                                                                              jsonb_col                                                                               
----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  1 | {"data1": {"data2": "c30d04070302b82d9fc1ff9d6ff37fd2350104dc859747a39d4cf8f61a1c72cb1bfe7e25556185e8347a5e74dace36cecc08a1b115977b5cc0c9ccc4e0bfc46e71f20bb763cd"}}
  1. Get/use原值:
select pgp_sym_decrypt(decode(jsonb_col->'data1'->>'data2', 'hex'), 'pwd') decrypted_value FROM test_jsonb_crypto WHERE id = 1;
 decrypted_value 
-----------------
 test
  1. 使用 INSERT 语句插入编码数据:
INSERT INTO test_jsonb_crypto (jsonb_col) VALUES(jsonb_set('{"data1":{"data2":"insert_test"}}', '{"data1", "data2"}', ('"'||encode(pgp_sym_encrypt(('{"data1":{"data2":"insert_test"}}'::jsonb)->'data1'->>'data2', 'pwd'), 'hex')::varchar||'"')::jsonb));

在我的测试中,我使用了十六进制编码,因为它与 JSONB 结合使用时问题较小,可以尝试其他存储成本较低的编码。