Если вы хотите, чтобы кровавые подробности продолжали читать, в противном случае все, что я спрашиваю, - можете ли вы ограничить возможности пользователей выполнять команду EXPLAIN в их операторах SQL, что-то вроде GRANT EXPLAIN TO billy было бы неплохо, но не кажется, существует.
Моя цель - зашифровать данные в столбце, проиндексировать зашифрованный столбец, поскольку он может использоваться при поиске, и сохранить ключ шифрования скрытым от всех конечных пользователей (может жить с администраторами sys или администратором базы данных, видя его). Каковы некоторые способы сделать это в PostgreSQL, которые позволили бы это? И если нет способа сделать все это, что у вас есть, чтобы попытаться туда добраться? Мой текущий подход, перечисленный ниже, почти привел меня туда, но когда и по запросу выполняется план объяснения, ключ шифрования раскрывается. Вот почему мне интересно, можете ли вы ограничить доступ пользователей, которые могут использовать объяснение.
Итак, вот небольшая настройка, чтобы продемонстрировать, о чем я говорю.
Скажем, у меня есть некоторые данные, зашифрованные в столбце таблицы базы данных, этот столбец будет просматриваться через интерфейсные интерфейсы графического интерфейса пользователя или через специальные запросы pg_admin.
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)"
Единственное, о чем я могу думать, - это создать веб-сервисы для базы данных, которые не позволят пользователю напрямую взаимодействовать с базой данных. Но если приложение находится в разработке, было бы неплохо, если бы некоторые пользователи могли иногда использовать pg_admin, но не могли видеть все, например, объяснять планы. Эти пользователи не будут знать, что такое план объяснения, и никогда не будут их использовать.
Я продолжаю возвращаться к созданию веб-службы, которая оборачивает все запросы, необходимые для запуска в функции, которые вызываются через веб-службу, но требует дополнительного времени для выпуска в формальной среде разработки и убирает рекламу. Подходит для специальных запросов и добавляет еще один слой для обслуживания. Есть идеи? Спасибо