Предел PostgreSQL, кто может выполнять планы объяснения - PullRequest
2 голосов
/ 14 октября 2011

Если вы хотите, чтобы кровавые подробности продолжали читать, в противном случае все, что я спрашиваю, - можете ли вы ограничить возможности пользователей выполнять команду 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, но не могли видеть все, например, объяснять планы. Эти пользователи не будут знать, что такое план объяснения, и никогда не будут их использовать.

Я продолжаю возвращаться к созданию веб-службы, которая оборачивает все запросы, необходимые для запуска в функции, которые вызываются через веб-службу, но требует дополнительного времени для выпуска в формальной среде разработки и убирает рекламу. Подходит для специальных запросов и добавляет еще один слой для обслуживания. Есть идеи? Спасибо

1 Ответ

1 голос
/ 12 апреля 2012

На боковой ноте вы можете изменить

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 может это обработать), ваши целевые данные будут зашифрованы один раз, и будут расшифрованы только соответствующие столбцы.

Мы изменили условие where, поэтому план может измениться, можетпожалуйста, попробуйте и отправьте новый план?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...