[Информационная безопасность, PostgreSQL, Администрирование баз данных] Реализация ролевой модели доступа с использованием Row Level Security в PostgreSQL
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Развитие темы Этюд по реализации Row Level Secutity в PostgreSQL и для развернутого ответа на комментарий.
Использованная стратегия подразумевает использование концепции «Бизнес-логика в БД», что было чуть подробнее описано здесь — Этюд по реализация бизнес-логики на уровне хранимых функций PostgreSQL
Теоретическая часть отлично описана в документации Postgres Pro — Политики защиты строк. Ниже рассмотрена практическая реализация конкретной бизнес задачи — ролевая модель доступа к данным.
В статье ничего нового, нет скрытого смысла и тайных знаний. Просто зарисовка о практической реализации теоретической идеи. Если кому интересно — читайте. Кому не интересно — не тратьте свое время зря.
Постановка задачиНеобходимо разграничить доступ на просмотр/вставку/изменение/удаление документа в соответствии с ролью пользователя приложения. Под ролью подразумевается запись в таблице roles связанной отношением многие-ко-многим с таблицей users. Детали реализации таблиц, по причине тривиальности, опущены. Также опущены конкретные детали реализации связанные с предметной областью.
Реализация
Создаем роли, схемы, таблицу
Создание объектов БД
SPL
CREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store;
CREATE TABLE store.docs
(
id integer , --id документа
man_id integer , --id менеджера документа
stat_id integer , --id статуса документа
...
is_del BOOLEAN DEFAULT FALSE
);
ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id);
ALTER TABLE store.docs OWNER TO store ;
Создаем функции для реализации RLSПроверка возможности выполнить SELECT строки
check_select
SPL
CREATE OR REPLACE FUNCTION store.check_select ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE
result boolean ;
curr_pid integer ;
curr_stat_id integer ;
doc_man_id integer ;
BEGIN
-- DBA имеет доступ ко всем документам
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--Если документ имеет метку 'удален' - не показывать в выборке
SELECT
is_del
INTO
result
FROM
store.docs
WHERE
id = current_id ;
IF result = TRUE
THEN
RETURN FALSE ;
END IF ;
--------------------------------
--Получить id текущего пользователя
SELECT
service_function.get_curr_pid ()
INTO
curr_pid ;
--------------------------------
--Получить id менеджера документа
SELECT
man_id
INTO
doc_man_id
FROM
store.docs
WHERE
id = current_id ;
--------------------------------
--Если менеджер документа не текущий пользователь или менеджер не назначен
--добавить документ в выборку
IF doc_man_id != curr_pid OR doc_man_id IS NULL
THEN
RETURN TRUE ;
ELSE
--Получить текущий статус документа
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
--Если статус позволяет просмотреть документ - добавить документ в выборку
IF curr_statid = 4 OR curr_statid = 9
THEN
RETURN TRUE ;
ELSE
--Иначе - исключить документ из выборки
RETURN FALSE ;
END IF ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_select( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) FROM public;
GRANT EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) TO service_functions;
Проверка возможности выполнить INSERT строки
check_insert
SPL
CREATE OR REPLACE FUNCTION store.check_insert ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE
curr_role_id integer ;
BEGIN
--DBA может добавлять строку в любом случае
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--Получить id роли текущего пользователя
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
--Если роль допускает возможность создания нового документа
--разрешить
IF curr_role_id = 3 OR curr_role_id = 5
THEN
RETURN TRUE ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_insert( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) FROM public;
GRANT EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) TO service_functions;
Проверка возможности выполнить DELETE строки
check_delete
SPL
CREATE OR REPLACE FUNCTION store.check_delete ( current_id store.docs.id%TYPE )
RETURNS boolean AS $$
BEGIN
--Только DBA может удалять строку
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql
SECURITY DEFINER;
ALTER FUNCTION store.check_delete( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_delete( store.docs.id%TYPE ) FROM public;
Проверка возможности выполнить UPDATE строки.
update_using
SPL
CREATE OR REPLACE FUNCTION store.update_using ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
BEGIN
--Документы имеющие статус 'удален' - не редактируются
IF is_del
THEN
RETURN FALSE ;
ELSE
RETURN TRUE ;
END IF ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_using( store.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE ) TO service_functions;
update_check
SPL
CREATE OR REPLACE FUNCTION store.update_with_check ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
DECLARE
current_rid integer ;
current_statid integer ;
BEGIN
--DBA может просматривать строку
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--Получить id роли текущего пользователя
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
--Удаление документа - изменение признака
IF is_deleted
THEN
--Если роль пользователя ***
IF current_role_id = 3
THEN
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
--Документ в статусе *** нельзя удалить
IF current_status_id = 11
THEN
RETURN FALSE ;
ELSE
--Можно удалить документ в других статусах
RETURN TRUE ;
END IF ;
--Иначе , если роль пользователя ***
ELSIF current_role_id = 5
THEN
--Все статусы документа
RETURN TRUE ;
ELSE
--Другие пользователи не могут удалять документы
RETURN FALSE ;
END IF ;
ELSE
--Обновление документа разрешено
RETURN TRUE ;
END IF ;
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_with_check( store.docs.id%TYPE ) TO service_functions;
Включение политики Row Level Secutiry для таблицы.
ENABLE ROW LEVEL SECURITY
SPL
ALTER TABLE store.docs ENABLE ROW LEVEL SECURITY ;
CREATE POLICY doc_select ON store.docs FOR SELECT TO service_functions USING ( (SELECT store.check_select(id)) );
CREATE POLICY doc_insert ON store.docs FOR INSERT TO service_functions WITH CHECK ( (SELECT store.check_insert(id)) );
CREATE POLICY docs_delete ON store.docs FOR DELETE TO service_functions USING ( (SELECT store.check_delete(id)) );
CREATE POLICY doc_update_using ON store.docs FOR UPDATE TO service_functions USING ( (SELECT store.update_using(id , is_del )) );
CREATE POLICY doc_update_check ON store.docs FOR UPDATE TO service_functions WITH CHECK ( (SELECT store.update_with_check(id , is_del )) );
ИтогЭто работает.
Предложенная стратегия позволила перенести реализацию ролевой модели с уровня бизнес-функций на уровень хранения данных.
Функции могут быть использованы в качестве шаблона для реализации более изощренных моделей скрытия данных, если того требуют бизнес-требования.
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность, Социальные сети и сообщества, IT-компании] Вновь утечка: в сети оказались данные 235 миллионов пользователей Instagram, YouTube и TikTok
- [Информационная безопасность] «КОМРАД 4.0»: кросс-платформенная отечественная SIEM-система с дружественным интерфейсом и высокой производительностью
- [Информационная безопасность, Хакатоны, CTF] Реверс-инжиниринг программ, поиск веб-уязвимостей и две недели в Сочи: чего ждать студентам от «Кибервызова»
- [Информационная безопасность] Непрерывное тестирование безопасности и автоматическая оценка кибер-рисков с помощью платформы Cymulate
- [Информационная безопасность, Платежные системы, Хранение данных, Софт] Системы противодействия банковскому мошенничеству – что необходимо знать о решениях
- [Информационная безопасность, Разработка веб-сайтов, JavaScript] Как npm обеспечивает безопасность
- [PostgreSQL] Этюд по реализации Row Level Secutity в PostgreSQL
- [Информационная безопасность, Реверс-инжиниринг, Программирование микроконтроллеров, Производство и разработка электроники] Реверс embedded: трассировка кода через SPI-flash
- [PostgreSQL, Программирование, SQL, Администрирование баз данных] PostgreSQL Antipatterns: уникальные идентификаторы
- [Информационная безопасность, IT-инфраструктура, Управление проектами] Строим ролевую модель управления доступом. Часть вторая, «строительная»
Теги для поиска: #_informatsionnaja_bezopasnost (Информационная безопасность), #_postgresql, #_administrirovanie_baz_dannyh (Администрирование баз данных), #_postgresql, #_administrirovanie_baz_dannyh (администрирование баз данных), #_rls, #_informatsionnaja_bezopasnost (информационная безопасность), #_informatsionnaja_bezopasnost (
Информационная безопасность
), #_postgresql, #_administrirovanie_baz_dannyh (
Администрирование баз данных
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 10:07
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Развитие темы Этюд по реализации Row Level Secutity в PostgreSQL и для развернутого ответа на комментарий. Использованная стратегия подразумевает использование концепции «Бизнес-логика в БД», что было чуть подробнее описано здесь — Этюд по реализация бизнес-логики на уровне хранимых функций PostgreSQL Теоретическая часть отлично описана в документации Postgres Pro — Политики защиты строк. Ниже рассмотрена практическая реализация конкретной бизнес задачи — ролевая модель доступа к данным. В статье ничего нового, нет скрытого смысла и тайных знаний. Просто зарисовка о практической реализации теоретической идеи. Если кому интересно — читайте. Кому не интересно — не тратьте свое время зря.
Постановка задачиНеобходимо разграничить доступ на просмотр/вставку/изменение/удаление документа в соответствии с ролью пользователя приложения. Под ролью подразумевается запись в таблице roles связанной отношением многие-ко-многим с таблицей users. Детали реализации таблиц, по причине тривиальности, опущены. Также опущены конкретные детали реализации связанные с предметной областью. Реализация Создаем роли, схемы, таблицу Создание объектов БДSPLCREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store; CREATE TABLE store.docs ( id integer , --id документа man_id integer , --id менеджера документа stat_id integer , --id статуса документа ... is_del BOOLEAN DEFAULT FALSE ); ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id); ALTER TABLE store.docs OWNER TO store ; Создаем функции для реализации RLSПроверка возможности выполнить SELECT строки check_selectSPLCREATE OR REPLACE FUNCTION store.check_select ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE result boolean ; curr_pid integer ; curr_stat_id integer ; doc_man_id integer ; BEGIN -- DBA имеет доступ ко всем документам IF SESSION_USER = 'curr_dba' THEN RETURN TRUE ; END IF ; -------------------------------- --Если документ имеет метку 'удален' - не показывать в выборке SELECT is_del INTO result FROM store.docs WHERE id = current_id ; IF result = TRUE THEN RETURN FALSE ; END IF ; -------------------------------- --Получить id текущего пользователя SELECT service_function.get_curr_pid () INTO curr_pid ; -------------------------------- --Получить id менеджера документа SELECT man_id INTO doc_man_id FROM store.docs WHERE id = current_id ; -------------------------------- --Если менеджер документа не текущий пользователь или менеджер не назначен --добавить документ в выборку IF doc_man_id != curr_pid OR doc_man_id IS NULL THEN RETURN TRUE ; ELSE --Получить текущий статус документа SELECT stat_id INTO curr_statid FROM store.docs WHERE id = current_id ; --Если статус позволяет просмотреть документ - добавить документ в выборку IF curr_statid = 4 OR curr_statid = 9 THEN RETURN TRUE ; ELSE --Иначе - исключить документ из выборки RETURN FALSE ; END IF ; END IF ; -------------------------------- RETURN FALSE ; END $$ LANGUAGE plpgsql SECURITY DEFINER; ALTER FUNCTION store.check_select( store.docs.id%TYPE ) OWNER TO store ; REVOKE EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) FROM public; GRANT EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) TO service_functions; Проверка возможности выполнить INSERT строки check_insertSPLCREATE OR REPLACE FUNCTION store.check_insert ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE curr_role_id integer ; BEGIN --DBA может добавлять строку в любом случае IF SESSION_USER = 'curr_dba' THEN RETURN TRUE ; END IF ; -------------------------------- --Получить id роли текущего пользователя SELECT service_functions.current_rid() INTO curr_role_id ; -------------------------------- --Если роль допускает возможность создания нового документа --разрешить IF curr_role_id = 3 OR curr_role_id = 5 THEN RETURN TRUE ; END IF ; -------------------------------- RETURN FALSE ; END $$ LANGUAGE plpgsql SECURITY DEFINER; ALTER FUNCTION store.check_insert( store.docs.id%TYPE ) OWNER TO store ; REVOKE EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) FROM public; GRANT EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) TO service_functions; Проверка возможности выполнить DELETE строки check_deleteSPLCREATE OR REPLACE FUNCTION store.check_delete ( current_id store.docs.id%TYPE )
RETURNS boolean AS $$ BEGIN --Только DBA может удалять строку IF SESSION_USER = 'curr_dba' THEN RETURN TRUE ; END IF ; -------------------------------- RETURN FALSE ; END $$ LANGUAGE plpgsql SECURITY DEFINER; ALTER FUNCTION store.check_delete( store.docs.id%TYPE ) OWNER TO store ; REVOKE EXECUTE ON FUNCTION store.check_delete( store.docs.id%TYPE ) FROM public; Проверка возможности выполнить UPDATE строки. update_usingSPLCREATE OR REPLACE FUNCTION store.update_using ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$ BEGIN --Документы имеющие статус 'удален' - не редактируются IF is_del THEN RETURN FALSE ; ELSE RETURN TRUE ; END IF ; END $$ LANGUAGE plpgsql SECURITY DEFINER; ALTER FUNCTION store.update_using( store.docs.id%TYPE , boolean ) OWNER TO store ; REVOKE EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE , boolean ) FROM public; GRANT EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE ) TO service_functions; update_checkSPLCREATE OR REPLACE FUNCTION store.update_with_check ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$ DECLARE current_rid integer ; current_statid integer ; BEGIN --DBA может просматривать строку IF SESSION_USER = 'curr_dba' THEN RETURN TRUE ; END IF ; -------------------------------- --Получить id роли текущего пользователя SELECT service_functions.current_rid() INTO curr_role_id ; -------------------------------- --Удаление документа - изменение признака IF is_deleted THEN --Если роль пользователя *** IF current_role_id = 3 THEN SELECT stat_id INTO curr_statid FROM store.docs WHERE id = current_id ; --Документ в статусе *** нельзя удалить IF current_status_id = 11 THEN RETURN FALSE ; ELSE --Можно удалить документ в других статусах RETURN TRUE ; END IF ; --Иначе , если роль пользователя *** ELSIF current_role_id = 5 THEN --Все статусы документа RETURN TRUE ; ELSE --Другие пользователи не могут удалять документы RETURN FALSE ; END IF ; ELSE --Обновление документа разрешено RETURN TRUE ; END IF ; RETURN FALSE ; END $$ LANGUAGE plpgsql SECURITY DEFINER; ALTER FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) OWNER TO store ; REVOKE EXECUTE ON FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) FROM public; GRANT EXECUTE ON FUNCTION store.update_with_check( store.docs.id%TYPE ) TO service_functions; Включение политики Row Level Secutiry для таблицы. ENABLE ROW LEVEL SECURITYSPLALTER TABLE store.docs ENABLE ROW LEVEL SECURITY ;
CREATE POLICY doc_select ON store.docs FOR SELECT TO service_functions USING ( (SELECT store.check_select(id)) ); CREATE POLICY doc_insert ON store.docs FOR INSERT TO service_functions WITH CHECK ( (SELECT store.check_insert(id)) ); CREATE POLICY docs_delete ON store.docs FOR DELETE TO service_functions USING ( (SELECT store.check_delete(id)) ); CREATE POLICY doc_update_using ON store.docs FOR UPDATE TO service_functions USING ( (SELECT store.update_using(id , is_del )) ); CREATE POLICY doc_update_check ON store.docs FOR UPDATE TO service_functions WITH CHECK ( (SELECT store.update_with_check(id , is_del )) ); ИтогЭто работает. Предложенная стратегия позволила перенести реализацию ролевой модели с уровня бизнес-функций на уровень хранения данных. Функции могут быть использованы в качестве шаблона для реализации более изощренных моделей скрытия данных, если того требуют бизнес-требования. =========== Источник: habr.com =========== Похожие новости:
Информационная безопасность ), #_postgresql, #_administrirovanie_baz_dannyh ( Администрирование баз данных ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 10:07
Часовой пояс: UTC + 5