powered by simpleCommunicator - 2.0.41     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Странное поведение SECURITY DEFINER
4 сообщений из 4, страница 1 из 1
Странное поведение SECURITY DEFINER
    #40060854
Андрей Р.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте!
Есть web-приложение, разработанное на версии 9.3. Все пользователи ходят в базу под одним аккаунтом (stapp), у которого минимум прав - usage основных схем и выполнение в них хранимых процедур. Необходимые процедуры сгенерированы пользователем postgres и имеют параметр SECURITY DEFINER.
И все это благополучно работало, и я был уверен, что раз SECURITY DEFINER - значит внутри процедуры у меня права все есть. Но тут пришла пора перейти на версию 10. (Сейчас установлен 10.11 64 bit). И начались странности.
В некоторых процедурах стали вылетать ошибки "Нет доступа к схеме pg_catalog". Вот пример такой процедуры:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
CREATE OR REPLACE FUNCTION sp_ware_view(IN _ware integer)
  RETURNS TABLE(code int, w_type int, w_name varchar, material varchar, size varchar, descr varchar,
                unit varchar, picture varchar, weight numeric, price numeric, type_name varchar,
                amount numeric, ordered numeric, reserved numeric) AS
$BODY$
declare
  v_amnt numeric(15,4);
  v_ord  numeric(15,4) = -1.00;
  v_rsrv numeric(15,4) = -1.00;
  v_sent numeric(15,4);
begin
  Select Sum(a.amount) into v_amnt                    -- Всего на складах
    From w_amnt a Where a.w_code = _ware;

  Select Sum(os.amount) into v_ord                    -- Заказано в недоделанных заявках (в т.ч.
    From ord_spec os                                  -- может быть и отгружено)
    Join orders ord on os.order_id = ord.order_id
   Where os.w_code = _ware
     and ord.fn_date is NULL;

  Select Sum(ws.amount) into v_rsrv                   -- Отложено в неотгруженных накладных
    From wbs_out_spec ws
    Join wbs_out wb on ws.wbs_out_id = wb.wbs_out_id
   Where ws.w_code = _ware
     and wb.check_date is NULL;

  Select Sum(ws.amount) into v_sent                   -- Отгружено по накладным, относящимся
    From wbs_out_spec ws                              -- к недоделанным заявкам
    Join wbs_out wb on ws.wbs_out_id = wb.wbs_out_id
    Join orders ord on wb.order_id = ord.order_id
   Where ws.w_code = _ware
     and wb.check_date is not NULL
     and ord.fn_date is NULL;
  v_ord := Coalesce(v_ord, 0.00) - Coalesce(v_sent, 0.00);

  Return Query
    SELECT w.code, w.w_type, w.w_name, w.material, w.size, w.descr, w.unit, w.picture, w.weight,
           round(w.price, 2) as price, wt.wt_name as type_name, Coalesce(round(v_amnt, 2), 0.00), round(v_ord, 2), Coalesce(round(v_rsrv, 2), 0.00)
      From ware w
      Join w_type wt on w.w_type = wt.wt_id
     Where w.code = _ware;
  Return;
end
$BODY$
  LANGUAGE plpgsql VOLATILE SECURITY DEFINER;

ALTER FUNCTION sp_ware_view(integer)
  OWNER TO postgres;
GRANT EXECUTE ON FUNCTION sp_ware_view(integer) TO stapp;
GRANT EXECUTE ON FUNCTION sp_ware_view(integer) TO postgres;


Здесь ошибка происходит во втором Select (Select Sum(os.amount) into v_ord...) А также во всех последующих.
Поверхностный анализ показал, что не нравится серверу запрос, в котором вычисляется Sum(...) из нескольких таблиц, причем результат складывается в переменную. Для сравнения - часть другой процедуры, которая нормально работает:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
...
  Return Query
    SELECT ww.w_code, ww.w_type, ww.w_name, ww.material, ww.size, ww.descr, ww.picture,
           ww.wt_name, ww.unit, ww.amount, ww.rsrv, ww.amount - ww.rsrv as for_sale,
           case when ww.ord_all - ww.ord_shp > ww.amount then ww.ord_all - ww.ord_shp - ww.amount else NULL end as deficit,
           ww.weight, ww.price, ww.price, NULL::numeric(15,4) as quant
      From (
             Select w.code as w_code, w.w_type, w.w_name, w.material, w.size, w.descr, w.picture, wt.wt_name,
                    w.unit, Coalesce(round(wa.amnt, 2), 0.00) as amount, Coalesce(round(wr.rsrv, 2), 0.00) as rsrv,
                    Coalesce(round(oa.ord_all, 2), 0.00) as ord_all, Coalesce(round(os.ord_shp, 2), 0) as ord_shp,
                    w.weight, round(w.price, 2) as price
               From ware w
               Join w_type wt on w.w_type = wt.wt_id
               Left Join ( Select Sum(a.amount) as amnt, a.w_code                     -- Всего на складах
                             From w_amnt a Group by a.w_code ) wa on w.code = wa.w_code
               Left Join ( Select Sum(ws.amount) as rsrv, ws.w_code                   -- Отложено в неотгруженных накладных
                             From wbs_out_spec ws
                             Join wbs_out wb on ws.wbs_out_id = wb.wbs_out_id
                            Where wb.check_date is NULL
                            Group by ws.w_code ) wr on w.code = wr.w_code
               Left Join ( Select Sum(os.amount) as ord_all, os.w_code                -- Заказано в недоделанных заявках (в т.ч.
                             From ord_spec os                                         -- может быть и отгружено)
                             Join orders ord on os.order_id = ord.order_id
                            Where ord.fn_date is NULL
                            Group by os.w_code ) oa on w.code = oa.w_code
               Left Join ( Select Sum(ws.amount) as ord_shp, ws.w_code                -- Отгружено по накладным, относящимся
                             From wbs_out_spec ws                                     -- к недоделанным заявкам
                             Join wbs_out wb on ws.wbs_out_id = wb.wbs_out_id
                             Join orders ord on wb.order_id = ord.order_id
                            Where wb.check_date is not NULL
                              and ord.fn_date is NULL
                            Group by ws.w_code ) os on w.code = os.w_code
...


Подзапросы здесь практически те же, что в первой процедуре, но результат - таблица. И работает.
Понятно, что можно дать stapp права usage pg_catalog. (Хотя и не хотелось бы.) Другой вариант - переписать все процедуры, выкидывающие ошибки, заменив присваивание "Into" на весьма кудрявый подзапрос. С процедурой sp_ware_view это получилось. Но во-первых, их всего около сотни, во-вторых, запросы получатся плохо читаемые.
Есть ли другие варианты? А главное - что ему понадобилось в pg_catalog и почему он туда пошел не как postgres, а как stapp ? SECURITY DEFINER работает не совсем так, как я предполагал? Или можно что-нибудь настроить в сервере?
...
Рейтинг: 0 / 0
Странное поведение SECURITY DEFINER
    #40060858
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Р.,

Возможность работы хоть чего то в принципе хоть как то не имея доступа на usage в pg_catalog никогда не постулировалась и не обещалась.
Вот в 10той версии что то еще по этому поводу ломается.
То что оно вообще раньше хоть как то работало в таком режиме - это скорее ошибка была (не должно было с моей т.з.).

Так что правильный совет - никогда ни у кого не отбирать usage на pg_catalog (там много чудес может быть)
и вернуть usage на pg_catalog для public.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Странное поведение SECURITY DEFINER
    #40061182
Андрей Р.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А где в документации написано, что все пользователи должны обязательно иметь доступ на usage в pg_catalog ? Я такого не нашел, может быть, упустил?
И главный вопрос - почему SECURITY DEFINER не обеспечивает прав postgres (DEFINER) при работе процедуры?
...
Рейтинг: 0 / 0
Странное поведение SECURITY DEFINER
    #40061195
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Андрей Р.
А где в документации написано, что все пользователи должны обязательно иметь доступ на usage в pg_catalog ? Я такого не нашел, может быть, упустил?
И главный вопрос - почему SECURITY DEFINER не обеспечивает прав postgres (DEFINER) при работе процедуры?


pg_catalog - системная схема...и то что вообще позволяют на нее права менять - так у superuser 1000 методов себе в ногу выстрелить (вот вы нашли 1001й метод).
права на pg_* не меняются и грязными руками никакие изменения в pg_* включая права не делаются.
Никто не будет перечислять вещи которые НЕЛЬЗЯ делать с pg_* их там куда больше чем тех которые можно/безопасно делать...
По умолчанию в pg_catalog все имеют доступ - вы это изменили (под вашу же ответственность )) вот вам и прилетело.

Ну в общем случае например я бы сказал что для того чтобы начать запускать процедуру - ее сначала надо считать ее код и найти ее... а она в pg_catalog в таблице лежит куда доступа нет (вы же сами забрали)... и оно должно было вообще сразу говорить что не могу найти такую процедуру (по хорошему если бы все было сделано).


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Странное поведение SECURITY DEFINER
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]