привилегии postgresql Обеспечение вставки выполняется только с помощью функций - PullRequest
4 голосов
/ 11 октября 2011

Допустим, у меня есть таблица лиц, которая содержит только имя (varchar) и пользовательский клиент.

Мне бы хотелось, чтобы единственный способ для клиента вставить людей - это функция:

CREATE OR REPLACE FUNCTION add_a_person(a_name varying character)
  RETURNS void AS
$BODY$
BEGIN
    INSERT INTO persons VALUES(a_name);
END;
$BODY$
  LANGUAGE plpgsql VOLATILE COST 100;

Итак, я не хочу предоставлять клиенту привилегии на вставку для людей и даю привилегию на выполнение только для add_a_person.Но без этого я получил бы отказ в разрешении из-за использования вставки внутри функции.

Я не нашел пути к этому в документации postgres о предоставлении привилегий.Есть ли способ сделать это?

Ответы [ 3 ]

5 голосов
/ 11 октября 2011

Вы можете определить функцию с помощью SEFURITY DEFINER.Это позволит функции запускаться для пользователя с ограниченными правами, как если бы он имел более высокие права создателя функции (который должен быть в состоянии вставить в таблицу).

Последняя строка определения будет выглядеть следующим образомэто:

LANGUAGE plpgsql VOLATILE COST 100 SECURITY DEFINER;
1 голос
/ 17 июня 2014

Это немного упрощенно, но при условии, что запущены 9.2 или более поздние версии, это пример того, как проверить единственную разрешенную функцию, выполняющую вставку:

CREATE TABLE my_table (col1 text, col2 integer, col3 timestamp);

CREATE FUNCTION my_table_insert_function(col1 text, col2 integer) RETURNS integer AS $$
BEGIN
  INSERT INTO my_table VALUES (col1, col2, current_timestamp);
  RETURN 1;
END $$ LANGUAGE plpgsql;

CREATE FUNCTION my_table_insert_trigger_function() RETURNS trigger AS $$
DECLARE
  stack text;
  fn integer;
BEGIN
  RAISE EXCEPTION 'secured';
EXCEPTION WHEN OTHERS THEN
  BEGIN
    GET STACKED DIAGNOSTICS stack = PG_EXCEPTION_CONTEXT;
    fn := position('my_table_insert_function' in stack);
    IF (fn <= 0) THEN
      RAISE EXCEPTION 'Expecting insert from my_table_insert_function'
        USING HINT = 'Use function to insert data';
    END IF;
    RETURN new;
  END;
END $$ LANGUAGE plpgsql;

CREATE TRIGGER my_table_insert_trigger BEFORE INSERT ON my_table
FOR EACH ROW EXECUTE PROCEDURE my_table_insert_trigger_function();

И быстрый пример использования:

INSERT INTO my_table VALUES ('test one', 1, current_timestamp); -- FAILS
SELECT my_table_insert_function('test one', 1); -- SUCCEEDS

Вы захотите заглянуть в стек более подробно, если хотите, чтобы ваш код был более надежным, безопасным и т. Д. Конечно, возможны проверки для нескольких функций, но они требуют больше работы. Разделение стека на несколько строк и его синтаксический анализ могут быть довольно сложными, поэтому, возможно, вам понадобятся некоторые вспомогательные функции, если все станет сложнее.

Это просто доказательство концепции, но она делает то, что заявляет. Я ожидаю, что этот код будет довольно медленным, учитывая использование обработки исключений и проверки стека, поэтому не используйте его в критически важных для вашего приложения частях приложения. Это вряд ли подходит для случаев, когда операторы DML встречаются часто, но если безопасность важнее, чем производительность, сделайте это.

0 голосов
/ 12 октября 2011

Ответ Мэтью верен в том, что ОПРЕДЕЛИТЕЛЬ БЕЗОПАСНОСТИ позволит запускать функцию с привилегиями другого пользователя. Документация для этого в http://www.postgresql.org/docs/9.1/static/sql-createfunction.html

Почему вы пытаетесь реализовать безопасность таким образом? Если вы хотите применить некоторую логику к вставкам, я настоятельно рекомендую делать это с ограничениями. http://www.postgresql.org/docs/9.1/static/ddl-constraints.html

Если вы хотите существенно более высокий уровень логики, чем это может быть разумно реализовано в ограничениях, я бы предложил рассмотреть вопрос о создании уровня бизнес-логики между уровнем представления данных и уровнем хранения данных. Вы обнаружите, что масштабируемость требует этого практически мгновенно.

Если ваша цель - защитить от SQL-инъекций, то вы нашли способ, который может сработать, но для вас это будет огромная работа. Хуже того, это приводит к огромным объемам действительно бессмысленного кода, который должен синхронизироваться между изменениями схемы. Это довольно грубо, если вы пытаетесь сделать что-то гибкое. Вместо этого рассмотрите возможность использования среды программирования, которая использует преимущества PREPARE / EXECUTE, которые в значительной степени все из них на данный момент. http://www.postgresql.org/docs/9.0/static/sql-prepare.html

...