×
Мы обрабатываем cookies, чтобы сделать наш сайт удобнее и персонализированнее для вас. Подробнее: политика использования «cookies» и «политики конфиденциальности».

Для самостоятельной настройки ознакомьтесь с инструкцией

Дополнительные настройки cookies в браузерах

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

При отключении обработки cookie наш сайт продолжит функционировать, однако будут использоваться исключительно необходимые технические файлы, без которых работа ресурса невозможна.

Инструкция по отключению cookies
Принять
Настроить
Отклонить

ДОКУМЕНТАЦИЯ

Выберите версию, форк и язык для СУБД Digital Q.DataBase, чтобы прочитать или скачать всю документацию.
Техподдержка
Документация
Диасофт
Авторские права © 2016–2025 ООО "Диасофт Экосистема"
Скачать всю документацию:

2.2.9. Политики защиты строк

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

Когда для таблицы включена защита строк (с помощью ALTER TABLE ... ENABLE ROW LEVEL SECURITY), любой обычный доступ к таблице для выборки или изменения строк должен быть разрешен политикой защиты строк. (Однако на владельца таблицы политики защиты строк обычно не распространяются.) Если для таблицы не существует ни одной политики, применяется политика запрета по умолчанию, что означает невозможность просмотра или изменения любых строк. Операции, применимые ко всей таблице, такие как TRUNCATE и REFERENCES, не подлежат защите строк.

Политики защиты строк могут применяться к конкретным командам, ролям или к обоим объектам одновременно. Политику можно настроить для применения к ALL командам, или к SELECT, INSERT, UPDATE, или DELETE. Одной политике может быть назначено несколько ролей; при этом применяются стандартные правила членства в ролях и наследование.

Чтобы определить, какие строки доступны для просмотра или изменения согласно политике, необходимо выражение, возвращающее логическое значение. Данное выражение будет вычисляться для каждой строки до применения любых условий или функций из запроса пользователя. (Единственным исключением из этого правила являются leakproof функции, которые гарантированно не допускают утечки информации; планировщик может применить такие функции перед проверкой защиты строк.) Строки, для которых выражение не возвращает true , обрабатываться не будут. Для независимого управления видимостью строк и возможностью их изменения могут быть указаны отдельные выражения. Выражения политик выполняются в составе запроса с привилегиями пользователя, инициировавшего этот запрос, хотя для доступа к данным, недоступным вызывающему пользователю, могут использоваться функции типа security-definer.

Суперпользователи и роли с BYPASSRLS атрибут всегда позволяет обходить систему защиты строк при доступе к таблице. Владельцы таблиц обычно также обходят систему защиты строк, хотя владелец таблицы может выбрать применение защиты строк с помощью команды ALTER TABLE ... FORCE ROW LEVEL SECURITY.

Включение и отключение защиты строк, равно как и добавление политик к таблице, является исключительным правом только владельца таблицы.

Политики RLS создаются с помощью CREATE POLICY команды, изменяются с помощью ALTER POLICY команды, а удаляются с помощью DROP POLICY команды. Для включения или отключения защиты строк для конкретной таблицы используйте команду ALTER TABLE команды.

Каждая политика RLS имеет имя; для одной таблицы может быть определено несколько таких политик. Поскольку политики привязаны к конкретным таблицам, каждая политика для таблицы должна иметь уникальное имя. Разные таблицы могут иметь политики с одинаковыми именами.

Если к конкретному запросу применяются несколько политик, они объединяются с помощью OR (для разрешающих политик, которые используются по умолчанию) или с использованием AND (для ограничивающих политик). Это аналогично правилу, согласно которому роль обладает всеми Привилегиями тех ролей, участником которых она является. Различия между разрешающими и ограничивающими политиками рассматриваются ниже.

В качестве простого примера рассмотрим создание политики для account отношения, которая разрешает доступ только членам managers роль для доступа к строкам, причем только к строкам их собственных учетных записей:

CREATE TABLE accounts (manager text, company text, contact_email text);

ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;

CREATE POLICY account_managers ON accounts TO managers
    USING (manager = current_user);

Приведенная выше политика неявно предоставляет WITH CHECK предложение, идентичное его USING предложению, так что ограничение применяется как к строкам, выбираемым командой (чтобы менеджер не мог SELECT, UPDATE, или DELETE существующие строки, принадлежащие другому менеджеру), так и к строкам, изменяемым командой (чтобы строки, принадлежащие другому менеджеру, не могли быть созданы с помощью INSERT или UPDATE).

Если роль не указана или используется специальное имя пользователя ключевое слово PUBLIC PUBLIC, то политика применяется ко всем пользователям в системе. Чтобы разрешить всем пользователям доступ только к их собственным строкам в таблице users может быть использована простая политика:

CREATE POLICY user_policy ON users
    USING (user_name = current_user);

Это работает аналогично предыдущему примеру.

Для использования различных политик для строк, добавляемых в таблицу, по сравнению с видимыми строками, можно комбинировать несколько политик. Эта пара политик позволит всем пользователям просматривать все строки в таблице users таблицы, но изменять только свои собственные:

CREATE POLICY user_sel_policy ON users
    FOR SELECT
    USING (true);
CREATE POLICY user_mod_policy ON users
    USING (user_name = current_user);

В SELECT команде эти две политики объединяются с помощью OR, в результате чего могут быть выбраны все строки. В других типах команд применяется только вторая политика, поэтому результат остается таким же, как и прежде.

Защита строк также может быть отключена с помощью ALTER TABLE команды. Отключение защиты строк не удаляет политики, определенные для таблицы; они просто игнорируются. Тогда все строки в таблице становятся видимыми и доступными для изменения в соответствии со стандартной системой привилегий SQL.

Ниже приведен более развернутый пример того, как эта функциональность может быть использована в производственных средах. Таблица passwd эмулирует файл паролей Unix:

-- Простой пример на основе файла passwd
CREATE TABLE passwd (
  user_name             text UNIQUE NOT NULL,
  pwhash                text,
  uid                   int  PRIMARY KEY,
  gid                   int  NOT NULL,
  real_name             text NOT NULL,
  home_phone            text,
  extra_info            text,
  home_dir              text NOT NULL,
  shell                 text NOT NULL
);

CREATE ROLE admin;  -- Администратор
CREATE ROLE bob;    -- Обычный пользователь
CREATE ROLE alice;  -- Обычный пользователь

-- Заполнение таблицы
INSERT INTO passwd VALUES
  ('admin','xxx',0,0,'Admin','111-222-3333',null,'/root','/bin/dash');
INSERT INTO passwd VALUES
  ('bob','xxx',1,1,'Bob','123-456-7890',null,'/home/bob','/bin/zsh');
INSERT INTO passwd VALUES
  ('alice','xxx',2,1,'Alice','098-765-4321',null,'/home/alice','/bin/zsh');

-- Обязательно включите защиту на уровне строк для этой таблицы
ALTER TABLE passwd ENABLE ROW LEVEL SECURITY;

-- Создание политик
-- Администратор может видеть все строки и добавлять любые строки
CREATE POLICY admin_all ON passwd TO admin USING (true) WITH CHECK (true);
-- Обычные пользователи могут просматривать все строки
CREATE POLICY all_view ON passwd FOR SELECT USING (true);
-- Обычные пользователи могут обновлять свои собственные записи, но
-- ограничим выбор оболочек, доступных обычному пользователю
CREATE POLICY user_mod ON passwd FOR UPDATE
  USING (current_user = user_name)
  WITH CHECK (
    current_user = user_name AND
    shell IN ('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh')
  );

-- Предоставление администратору всех стандартных прав
GRANT SELECT, INSERT, UPDATE, DELETE ON passwd TO admin;
-- Пользователи получают доступ на чтение только к общедоступным столбцам
GRANT SELECT
  (user_name, uid, gid, real_name, home_phone, extra_info, home_dir, shell)
  ON passwd TO схема public;
-- Разрешение пользователям обновлять определенные столбцы
GRANT UPDATE
  (pwhash, real_name, home_phone, extra_info, shell)
  ON passwd TO схема public;

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

-- администратор может просматривать все строки и поля
postgres=> set role admin;
SET
postgres=> table passwd;
 user_name | pwhash | uid | gid | real_name |  home_phone  | extra_info | home_dir    |   shell
-----------+--------+-----+-----+-----------+--------------+------------+-------------+-----------
 admin     | xxx    |   0 |   0 | Admin     | 111-222-3333 |            | /root       | /bin/dash
 bob       | xxx    |   1 |   1 | Bob       | 123-456-7890 |            | /home/bob   | /bin/zsh
 alice     | xxx    |   2 |   1 | Alice     | 098-765-4321 |            | /home/alice | /bin/zsh
(3 строки)

-- Проверка того, что доступно пользователю Alice
postgres=> set role alice;
SET
postgres=> table passwd;
ERROR:  permission denied for table passwd
postgres=> select user_name,real_name,home_phone,extra_info,home_dir,shell from passwd;
 user_name | real_name |  home_phone  | extra_info | home_dir    |   shell
-----------+-----------+--------------+------------+-------------+-----------
 admin     | Admin     | 111-222-3333 |            | /root       | /bin/dash
 bob       | Bob       | 123-456-7890 |            | /home/bob   | /bin/zsh
 alice     | Alice     | 098-765-4321 |            | /home/alice | /bin/zsh
(3 строки)

postgres=> update passwd set user_name = 'joe';
ОШИБКА:  отказано в доступе к таблице passwd
-- Алисе разрешено изменять её собственное имя real_name, но не чужие
postgres=> update passwd set real_name = 'Alice Doe';
UPDATE 1
postgres=> update passwd set real_name = 'John Doe' where user_name = 'admin';
UPDATE 0
postgres=> update passwd set shell = '/bin/xx';
ОШИБКА:  новая строка нарушает WITH CHECK OPTION для «passwd»
postgres=> delete from passwd;
ОШИБКА:  отказано в доступе к таблице passwd
postgres=> insert into passwd (user_name) values ('xxx');
ОШИБКА:  отказано в доступе к таблице passwd
-- Алиса может изменить свой собственный пароль; Политика RLS неявно предотвращает обновление других строк
postgres=> update passwd set pwhash = 'abc';
UPDATE 1

Все созданные до настоящего момента политики были разрешающими; это означает, что при применении нескольких политик они объединяются с использованием «OR» Логический оператор. Хотя разрешающие политики могут быть настроены так, чтобы разрешать доступ к строкам только в определенных случаях, может быть проще сочетать разрешающие политики с ограничивающими (которым должны соответствовать записи и которые объединяются с помощью «AND» логического оператора). В дополнение к приведенному выше примеру мы добавим ограничительную политику, требующую подключения администратора через локальный сокет Unix для доступа к записям passwd таблицы:

CREATE POLICY admin_local_only ON passwd AS RESTRICTIVE TO admin
    USING (pg_catalog.inet_client_addr() IS NULL);

В результате администратор, подключающийся по сети, не увидит никаких записей из-за действия ограничивающей политики:

=> SELECT current_user;
 current_user
--------------
 admin
(1 строка)

=> select inet_client_addr();
 inet_client_addr
------------------
 127.0.0.1
(1 строка)

=> TABLE passwd;
 user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell
-----------+--------+-----+-----+-----------+------------+------------+----------+-------
(0 строк)

=> UPDATE passwd set pwhash = NULL;
UPDATE 0

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

В некоторых ситуациях важно быть уверенным в том, что защита строк не применяется. Например, при создании резервной копии последствия могут быть катастрофическими, если из-за защиты строк часть строк будет незаметно пропущена. В такой ситуации можно установить row_security параметр конфигурации в значение off. Это само по себе не отменяет защиту строк; вместо этого будет выдана ошибка, если результаты любого запроса будут отфильтрованы политикой. После этого причину ошибки можно исследовать и устранить.

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

-- определение привилегированных групп
CREATE TABLE groups (group_id int PRIMARY KEY,
                     group_name text NOT NULL);

INSERT INTO groups VALUES
  (1, 'low'),
  (2, 'medium'),
  (5, 'high');

GRANT ALL ON groups TO alice;  -- alice является администратором
GRANT SELECT ON groups TO PUBLIC;

-- определение уровней привилегий пользователей
CREATE TABLE users (user_name text PRIMARY KEY,
                    group_id int NOT NULL REFERENCES groups);

INSERT INTO users VALUES
  ('alice', 5),
  ('bob', 2),
  ('mallory', 2);

GRANT ALL ON users TO alice;
GRANT SELECT ON users TO public;

-- таблица, содержащая защищаемую информацию
CREATE TABLE information (info text,
                          group_id int NOT NULL REFERENCES groups);

INSERT INTO information VALUES
  ('barely secret', 1),
  ('slightly secret', 2),
  ('very secret', 5);

ALTER TABLE information ENABLE ROW LEVEL SECURITY;

-- строка должна быть видима или доступна для обновления пользователям, чей идентификатор group_id безопасности
-- больше или равен идентификатору group_id строки
CREATE POLICY fp_s ON information FOR SELECT
  USING (group_id <= (SELECT group_id FROM users WHERE user_name = current_user));
CREATE POLICY fp_u ON information FOR UPDATE
  USING (group_id <= (SELECT group_id FROM users WHERE user_name = current_user));

-- для защиты таблицы information мы полагаемся только на политику RLS
GRANT ALL ON information TO public;

Теперь предположим, что alice хочет изменить «слегка секретную» информацию, но решает, что Мэллори Мэллори не следует доверять новое содержимое этой строки, поэтому она выполняет следующее:

BEGIN;
UPDATE users SET group_id = 1 WHERE user_name = 'mallory';
UPDATE information SET info = 'secret from mallory' WHERE group_id = 2;
COMMIT;

Это выглядит безопасным; здесь нет временного окна, в котором Мэллори Мэллори могла бы увидеть «secret from mallory» строку. Однако здесь возникает состояние гонки. Если Мэллори Мэллори одновременно выполняет, скажем,

SELECT * FROM information WHERE group_id = 2 FOR UPDATE;

и её транзакция выполняется с уровнем изоляции READ COMMITTED режиме, она может увидеть «secret from mallory». Это происходит, если её транзакция достигает информации строку сразу после того, как aliceэто сделает транзакция пользователя. Она блокируется в ожидании того, когда aliceзавершит транзакцию, а затем извлекает обновлённое содержимое строки благодаря FOR UPDATE предложению. Однако она не а не извлекает обновлённую строку для неявного SELECT из users, так как этот подзапросSELECT не содержал FOR UPDATE; вместо этого строка users считывается по снимку данных, сделанному в начале выполнения запроса. Следовательно, выражение политики проверяет старое значение Мэллориуровня прав доступа и позволяет ей видеть обновлённую строку.

Существует несколько способов решения этой проблемы. Одним из простых решений является использование SELECT ... FOR SHARE в под-SELECTв политиках защиты строк. Однако это требует предоставления UPDATE привилегии для целевой таблицы (в данном случае users) соответствующим пользователям, что может быть нежелательным. (При этом может быть применена другая политика защиты строк, чтобы предотвратить фактическое использование этой привилегии; также под-SELECT может быть встроен в функцию с определителем безопасности — SECURITY DEFINER.) Кроме того, интенсивное одновременное использование блокировок типа ROW SHARE для целевой таблицы может привести к снижению производительности, особенно при частом её обновлении. Другим решением, целесообразным при редких обновлениях целевой таблицы, является использование ACCESS EXCLUSIVE блокировки целевой таблицы при её обновлении, чтобы ни одна параллельная транзакция не могла считывать старые значения строк. Кроме того, можно дождаться завершения всех параллельных транзакций после фиксации обновления целевой таблицы, прежде чем вносить изменения, основанные на новых условиях безопасности.

Для получения дополнительных сведений см. CREATE POLICY и ALTER TABLE.

Наверх
свяжитесь
с нами
контакты
Для прямой связи с нами вы можете использовать контакты ниже, либо оставить заявку через форму обратной связи, и мы обязательно свяжемся с вами

*поля обязательные к заполнению