如果你想要血腥的细节继续阅读,否则所有我问的是你是否可以限制用户能够在他们的SQL语句上运行EXPLAIN命令,像GRANT EXPLAIN to billy这样的东西会很好,但是不会似乎存在。
我的目标是加密列中的数据,索引加密列,因为它可以用于搜索,并保持加密密钥对所有最终用户隐藏(可以与sys管理员或DBA看到它)。在PostgreSQL中有哪些方法可以实现这一点?如果没有办法完成所有这些,你有什么东西可以到达那里?我下面列出的当前方法几乎让我在那里,但是当查询计划运行时,会显示加密密钥。这就是为什么我想知道你是否可以限制能够使用explain的用户访问。
所以这里是一个小小的设置,以展示我在说什么。 假设我在数据库表的一列中加密了一些数据,将通过gui前端屏幕或pg_admin ad-hoc查询搜索此列。
CREATE TABLE test(id serial,my_data TEXT);
--Fill table with enough data to need an index.
DO $$
DECLARE counter INTEGER := 0;
BEGIN
WHILE(counter < 1000)
LOOP
EXECUTE 'INSERT INTO test(my_data)
SELECT pgp_sym_encrypt(''avalue' || CAST(counter AS TEXT) || '''' || ', ''apasswordwithsomeentropy'',''compress-algo=1, cipher-algo=aes256'');';
counter := counter + 1;
END LOOP;
END$$;
ANALYZE test;
CREATE INDEX index1
ON test
USING btree
(my_data);
这个选择仍然需要进行全表扫描,我想避免这种情况。
SELECT id,
my_data,
pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy')
FROM test
WHERE pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy') = 'avalue114';
"Seq Scan on test (cost=0.00..665.00 rows=61 width=246)"
" Filter: (pgp_sym_decrypt((my_data)::bytea, 'apasswordwithsomeentropy'::text) = 'avalue114'::text)"
那么如果我使用函数索引来加速这个查询呢?我使用get_password函数没有使用密码硬编码创建索引。请记住,我不希望用户查看索引定义并查看密码。假设用户无法从密码中选择或执行get_password(),则只有一个具有额外权限的帐户可以。并且get_password()函数仅在函数索引中使用。所以我的理解是用户不需要该函数的执行权限吗?
CREATE TABLE password
(
password_id serial NOT NULL,
password_value text
);
INSERT INTO password(password_value)
SELECT 'apasswordwithsomeentropy';
from get_password();
CREATE FUNCTION get_password() RETURNS TEXT
AS 'select password_value
from password
where password_id = 1'
LANGUAGE SQL
IMMUTABLE;
CREATE INDEX index2 ON test (pgp_sym_decrypt(cast(my_data as bytea),get_password()));
现在,当我运行select时,数据库使用index2,我得到的结果很好,很快就像我想要的那样。问题是当我在选择查询上执行解释计划时,index2显示平面文本中的密码。
SELECT id,
my_data,
pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy')
FROM test
WHERE pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy') = 'avalue114';
"Bitmap Heap Scan on test (cost=4.73..171.49 rows=61 width=246)"
" Recheck Cond: (pgp_sym_decrypt((my_data)::bytea, 'apasswordwithsomeentropy'::text) = 'avalue114'::text)"
" -> Bitmap Index Scan on index2 (cost=0.00..4.72 rows=61 width=0)"
" Index Cond: (pgp_sym_decrypt((my_data)::bytea, 'apasswordwithsomeentropy'::text) = 'avalue114'::text)"
我唯一能想到的是为数据库创建Web服务,以防止用户直接与数据库交互。但是作为应用程序在内部,如果有些用户仍然可以偶尔使用pg_admin,但不会看到解释计划等所有内容,那将是很好的。这些用户不知道什么是解释计划,也不会使用它们。
我不断回过头来创建一个Web服务,它包含了在通过Web服务调用的函数中运行所需的所有查询,但这需要额外的时间才能在正式的开发环境中发布并带走广告 - 临时查询方法并添加另一个维护层。有任何想法吗?感谢
答案 0 :(得分:1)
在旁注中您可能想要更改
SELECT id,
my_data,
pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy')
FROM test
WHERE pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy') = 'avalue114';
到
SELECT id,
my_data,
pgp_sym_decrypt(cast(my_data as bytea),'apasswordwithsomeentropy')
FROM test
WHERE pgp_sym_encrypt(cast('avalue114' as bytea),'apasswordwithsomeentropy') = my_data;
这样postgres不需要解密每个my_data进行比较。如果pgp_sym_encrypt是确定性的并且可以被缓存(不确定postgres是否可以处理这个),那么您的目标数据将被加密一次,只有匹配的列才会被解密。
我们已经更改了地点条件,因此计划可能会发生变化,您可以尝试发送新计划吗?