Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

2005 г.

Защита на уровне строк
Часть 1

Джонатан Льюис (Jonathan Lewis)
www.jlcomp.demon.co.uk

Перевод: Валерий Кравчук, OpenXS Initiative

В этой короткой серии статей я буду рассматривать все более тонкие и строгие уровни защиты строк, которые можно установить для данных в Oracle 8 и 9. В части 1 я начну с контекстов и триггеров на регистрацию. В части 2 я перейду к возможностям "официальной" защиты RLS (также известной как детальный контроль доступа или виртуальная приватная база данных), появившейся в Oracle. Наконец, в части 3 я рассмотрю предложенный корпорацией Oracle способ расширения RLS для реализации label security. Все примеры кода в этих статьях были протестированы с помощью Oracle 9.2.0.3.

История

С момента появления триггеров в Oracle было легко реализовать простой вид контроля доступа к данным на основе имени пользователя, комбинируя таблицу, представление и триггер. Рассмотрим, например, представленный ниже код:

create table public_table (
  id			number(6),
  v1			varchar2(30),
  owner			varchar2(32));
  
create or replace trigger pt_bri
  before insert on public_table
  for each row
begin
  new.owner := user;
end;
/

create or replace view private_view as
  select id, v1
    from public_table
   where owner = user;

grant insert, select, update, delete on private_view to public;

Если теперь создать пару пользователей с привилегией create session, вы увидите, что они могут выбирать, вставлять, изменять и удалять строки из представления private_view (если они не забудут указать имя схемы, которой он принадлежит), но увидеть они смогут только строки, которые они создали сами. Они не смогут увидеть строки друг друга. Триггер гарантирует, что имя пользователя, создающего строку, добавляется к строке; условие "owner = user" гарантирует, что только исходный создатель строки сможет ее увидеть.

(Учтите - строка pl/sql-кода :new.owner := user приведет к выполнению "select user from dual", так что, в эффективной производственной системе, вероятно, придется использовать более "хитрый" код).

Только владелец таблицы сможет увидеть все строки; но это потому, что владелец таблицы может запрашивать непосрредственно таблицу, а не ограничиваться представлением. Фактически, у нас есть один, фиксированный текст представления, который интерпретируется по-разному во время выполнения, из-за "псевдо-параметра" user, который появляется в его определении.

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

Конечно, основанный на группах механизм вроде описанного тоже можно было реализовать давно, и обычно для реализации использовалась функция в пакете, которую можно было использовать как в представлении, так и в триггере практически так же, как выше использовался псевдостолбец user. Но этот метод требует значительных дополнительных ресурсов из-за большого количества вызовов функции пакета, которые необходимы (по одному вызову на каждую затрагиваемую строку). Эта специфическая проблема производительности исчезла, когда в Oracle 8.1 появились "переменные среды" и вызов sys_context().

С этой версии, если в вашем коде используются вызовы функции userenv(), вы должны стараться вместо нее использовать вызов sys_context() для контекста 'userenv'. Например:

select sys_context('userenv', 'sessionid') from dual;

вместо

select userenv('sessionid') from dual;

Функция userenv() является устаревшей, а контекст 'userenv' имеет намного больше опций.

Контексты

Идея, лежащая в основе использования контекстов, очень проста и обеспечивает серьезную защиту. В исходном виде ее можно определить тремя особенностями: (i) контекст - список переменных в памяти, значения которых привязаны к сеансам, (ii) сеанс может получить текущие значения этих переменных, вызывая функцию sys_context(), (iii) переменные в контексте могут устанавливаться только путем вызова процедуры, связанной с этим контекстом. Например, используя служебную таблицу защиты, можно переписать предыдущий код следующим образом:

create or replace context security_ctx
    using security_proc;        -- Процедура, защищающая контекст.
                                -- Это может быть процедура пакета.

create or replace procedure security_proc as
    m_group_id  varchar2(32);
begin          -- должна включать обработку исключительных ситуаций
    select  group_id
    into    m_group_id
    from    security_table      -- эту таблицу надо создать.
    where   user_name = user;
    dbms_session.set_context(
        namespace   => 'SECURITY_CTX',
        attribute   => 'GROUP_ID',
        value       => m_group_id
    );
end;
/

create or replace trigger pt_bri 
before insert on public_table
for each row
begin
    :new.owner := sys_context('security_ctx','group_id');
    -- должна включать перехват ошибок, например, null-значений
end;
/

create or replace view private_view as
select      id, v1
from        public_table
where       owner = sys_context('security_ctx','group_id');

grant insert, select, update, delete on private_view to public;

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

Для завершения картины надо использовать триггеры на регистрацию. Например, в схеме, в которой создана таблица, процедура и представление, можно выполнить следующий код:

create or replace trigger security_trigger
after logon on database
begin
    security_proc;
end;
/

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

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

Поэтому вы не должны использовать этот механизм, не учитывая и не проверив влияние на производительность - в частности, на процессы пакетной загрузки. Помните также, что вы можете найти примеры SQL-операторов, для которых оптимизатор вырабатывает менее эффективный способ выполнения, поскольку в коде приложения теперь надо использовать представление (private_view), а не таблицу (public_table), как раньше.

Будьте очень внимательны при написании триггеров на регистрацию, всегда тестируйте их на одной схеме (конструкция after logon on test_user.schema создаст триггер на регистрацию в схеме test_user), пррежде чем создавать их на уровне базы данных, или придется подключаться как SYS>, чтобы решить проблему, если что-то пойдет не так.

Для создания и удаления контекстов вам потребуются привилегии:

   create any context
   drop any context

А для создания и удаления триггеров базы данных необходима привилегия

   administer database trigger

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

select namespace, attribute, value
from sys.v_$context 
order by namespace, attribute;

NAMESPACE            ATTRIBUTE         VALUE
-------------------- ----------------- -----------
SECURITY_CTX         GROUP_ID          T

Вывод

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

Часть 2: Правила защиты


Джонатан Льюис (Jonathan Lewis) - независимый консультант с более чем 18-летним опытом использования Oracle. Он специализируется на физическом проектировании баз данных и стратегии использования сервера Oracle. Джонатан - автор книги "Practical Oracle 8i - Building Efficient Databases", опубликованной издательством Addison-Wesley, и один из наиболее известных лекторов среди специалистов по Oracle в Великобритании. Подробнее о его публикациях, презентациях и семинарах можно узнать на сайте www.jlcomp.demon.co.uk, где также находится список ЧаВО The Co-operative Oracle Users' FAQ по дискуссионным группам Usenet, связанным с СУБД Oracle.

Эта статья первоначально была опубликована на сайте DBAzine.com, сетевом портале, посвященном проблемам различных СУБД и их решениям. Перевод публикуется с разрешения автора.

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...