СТАТЬЯ
17.01.02

<< Часть 1

Профессионалу разработчику. Безопасность без размножения баз данных: виртуальные частные базы данных Oracle (Часть 2)

 © Стефан Линдблад, (Stefan Lindblad, Oracle Corporation)
Статья была опубликована в журнале OracleMagazine
 
Политики меток безопасности Oracle
 
Oracle Label Security базируется на концепции политики управления доступом на основе меток – label based access control (LBAC) policy. Используя метки безопасности Oracle, пользователи для каждой политики определяют и ассоциируют метки и авторизацию пользователей. Для определения меток администратор безопасности использует графический интерфейс – Oracle Policy Manager. Затем политика безопасности прикрепляется ко всему приложению или отдельным таблицам приложения, и выполняется авторизация меток для пользователей. Например, в базе данных Oracle9i можно определить политики Defense (оборона) и Human Resources (трудовые ресурсы). В политике Defense могут быть определены метки: Secret (секретно), Top Secret (совершенно секретно) и Confidential (конфиденциально). В политике Human Resources могут быть определены метки: Senior VP (старший вице-президент), Manager (менеджер) и HR Only (только сотрудники отдела трудовых ресурсов).
 
Метки безопасности в Oracle Label Security
 
Метку безопасности в Oracle Label Security можно рассматривать как дополнительный атрибут таблицы. Метка добавляется к определению базовой таблицы приложения и используется Oracle Label Security для принудительной поддержки разграничения доступа. Проектирование меток Oracle Label Security – одно из ключевых архитектурных средств, которое позволяет заказчикам реализовывать сложное управление доступом. Каждая метка безопасности Oracle состоит из трех компонентов:
 
·      одного иерархического уровня защиты или категории допуска (грифа секретности),
·      одного или более горизонтального компартмента (отсека, отделения) или категории
·      одной или более групп.
 
Компоненты меток
 
Level  (уровень) – иерархический компонент, указывающий секретность (критичность) данных. В типичных правительственных организациях могут быть определены следующие уровни:
 
·        конфиденциально,
·        секретно
·        совершенно секретно.
 
Однако никаких ограничений на количество уровней нет. Коммерческие организации могут иметь, например, только один уровень для корпоративных конфиденциальных данных или потребностей хостинга приложений.
 
Compartment  (компартмент) – этот компонент иногда называется категорией, и он не является иерархическим. Обычно для разделения (“отсечения”) данных определяется один или более компартментов. Например, компартмент может быть определен для текущей стратегической инициативы или для отображения абонентов (пользователей) арендуемого приложения. Данные, связанные с инициативой, могут быть помечены вновь определенным компартментом. Oracle Label Security поддерживает до 9999 компартментов.
 
Group  (группа) – этот компонент может быть иерархическим и используется для регистрации принадлежности данных. Например, могут быть созданы две группы: Senior VP и Manager, и затем назначены, как дочерние, группе CEO (председатель правления), образуя дерево принадлежности. Метки могут состоять из единственного компонента – уровня, или уровень может быть объединен с компартментами и/или группам.
 
Теги меток
 
Теги меток  хранятся вместе с данными (в целях оптимизации). Ниже показан пример таблицы приложения с четырьмя атрибутами:
 
Employee Number (табельный номер служащего),
Hire Date (дата приема на работу),
Grade (ранг)
Department (отдел).
Пятый и последний атрибут – Subscriber Label (метка абонента) – добавлен Oracle Label Security.
 
Перечисленные ниже значения этого атрибута представляют собой внешнее представление меток.
 
Внешнее представление
 
Внешнее представление меток составляют три компонента меток, разделенные двоеточиями. Метка Business-On-Line: ACME: Senior VP состоит из следующих компонентов:
 
·        Level (уровень) = Business-On-Line
·        Compartment (компартмент) = ACME
·        Group (группа) = Senior VP
 
Пример таблицы приложения:

Employee

Hire Date

Grade  Department

Subscriber Label

12345

Sep 12, 1999   3

Engineering

Business-on-line: ACME: Manager

45673

Apr 01, 1984   5

Human Resources

Business-on-line: ACME: Manager

32100

July 03, 1991   2

Finance

Business-on-line: ACME: Senior VP

 
Все метки в примере имеют один и тот же уровень, Business-On-Line, и один и тот же компартмент, ACME. А в компоненте группы показано два возможных значения, Manager и Senior VP. Например, предположим, что администратор безопасности определил группу Senior VP как родительскую группу группы Manager.
 
Этот короткий пример не дает полного описания Oracle Label Security. Он помещен здесь, чтобы показать сходство с виртуальными частными базами данных.
 
Перемещение нескольких узлов баз данных в один
 
Одна из современных проблем – администрирование и его возрастающая сложность. Предпочтительно, чтобы все приложения работали в одной и той же базе данных. Если это не было сделано во время инсталляции на корпоративном уровне, то установка проработавшего некоторое время приложения может оказаться достаточно тяжелой.
 
Давайте сформулируем задачу и определим ограничения:
 
"Мы имеем десять узлов с базами данных, в которых работает одно и то же приложение, используемое как несколько локальных систем. Для облегчения администрирования, а также для обеспечения выдачи отчетов из приложения в целом, а не только части его, нам хочется перенести его на одну машину. Имеется также требование, чтобы данное OLTP-приложение, которое используют все конечные пользователи, не было изменено".
В данный момент нет никакой необходимости изменения приложения, все, что нужно сделать может быть сделано на уровне базы данных. Существует два способа решения:
 Эмуляция баз данных
 
Этот способ представляет собой самый простой,  на первый взгляд, путь миграции. Все, что нужной сделать – просто создать нового пользователя для каждого приложения, которое мы инсталлируем в базе данных. Это даст нам десять пользователей с одинаковым содержимым их схем, и в таблицах не требуется ничего изменять. При этом могут возникнуть проблемы:
Чтобы решить эти проблемы, мы, скорее всего, должны многое изменить в базе данных, и, возможно даже, переписать приложение. Однако этот вариант нас не устраивает.
 
Другое решение – создать в одной машине десять отдельных баз данных, но в таком случае мы по-прежнему будем иметь десять различных баз данных, которые нужно контролировать и создавать их резервные копии. Даже если некоторые процедуры, выполняемые на одной машине, упрощаются, мы не получим той простоты администрирования, на которую рассчитывали. Более того, сервер базы данных не будет работать столь же эффективно с 10 базами данных, как он работал с одной. Если мы имеем только одну базу данных, различные приложения могут совместно использовать такие ресурсы, как временные табличные пространства и табличные пространства с сегментами отката.
 
Виртуальная частная база данных
 
Используя такое решение Oracle, как виртуальные частные базы данных, мы можем объединить десять баз данных в одну без изменения чего-либо в приложении. Единственное, что мы должны изменить – информация для соединения клиента с сервером, и если для этого используется централизованная служба, это означает изменения только в этом службе.
 
Проблемы, которые могут возникнуть во время процесса миграции, в основном заключаются в дубликатах строк по отношению к информации первичных ключей. Например, в одном узле заказчик с идентификатором id1 является заказчиком Alpha, а в другом узле заказчик с таким же идентификатором id1 является заказчиком Beta. Это означает, что мы должны создать систему, которая может решать такие проблемы.
 
Миграция таблиц без дубликатов
 
Если информация из различных узлов не может содержать дубликатов, миграция будет простой. Возможно, что все узлы имели отдельные копии одних и тех же таблиц. Естественно, что в таком случае при миграции никаких особых действий предпринимать не нужно. Даже если совместное использование данных отсутствует, все что мы должны сделать – переместить данные в новую базу данных, поскольку первичные и уникальные ключи во время миграции не нарушаются.
 
Миграция таблиц с дубликатами
 
В этом случае имеются некоторые сложности. Для таблиц с дубликатами мы могли бы регенерировать информацию первичных ключей. Однако это может привести к существенному усложнению процесса миграции, если внешние ключи одних таблиц ссылаются на первичные ключи других таблиц и так далее. Намного проще добавить информацию в первичные ключи. К каждой таблице с дубликатами можно добавить новый столбец APPLICATION_ID, содержащий идентификаторы приложений в диапазоне от одного до десяти. Мы можем сделать это для таблиц CUSTOMER и INVOICE, которые были использованы в примере нашей виртуальной частной базы данных.
 

Проверим таблицу CUSTOMER в двух разных узлах.  

Узел 1:

SQL> select * from customer; 

       CUSTOMER_ID NAME                     LOGIN_ID
----------- ------------------------------ ----------
          1 Stefan Lindblad                STEFAN
          2 Nils Nilsson                   NISSE
          3 Scott King                     SCOTT
          4 John Smith                     JOHN

 Узел 2:
SQL> select * from customer;
 
       CUSTOMER_ID NAME                     LOGIN_ID
----------- ------------------------------ ----------
          1 Klas Andersson                 KLAS
          2 Eva Johansson                  EVA
          3 Joel Davids                    JOEL
          4 Clark Kent                     CLARK
Здесь мы видим, что дубликаты строк не дублируют заказчиков, а только их идентификаторы. Сейчас мы создадим новую таблицу для заказчиков, которую назовем CUSTOMER_TAB, а после этого – новое представление этой таблицы, которое назовем CUSTOMER. Созданная таблица будет иметь один добавленный столбец – APPLICATION_ID. Затем выполним миграцию данных в эту таблицу, копируя данные с каждого узла по отдельности:
SQL> insert into customer_tab (customer_id, application_id, name, login_id)
  2  select customer_id, 1 , name, login_id
  3  from customer_1;
 
4 rows created.
 
SQL> insert into customer_tab (customer_id, application_id, name, login_id)
  2  select customer_id, 2 , name, login_id
  3  from customer_2;
 
4 rows created.
 
SQL> alter table customer_tab
  2  add constraint pk_customer primary key (customer_id, application_id);
 
Table altered. 
Миграция данных закончена. Единственная проблема теперь состоит в том, что когда наше одно приложение запрашивает представление CUSTOMER, оно будет видеть дубликаты:
SQL> select * from customer;
 
       CUSTOMER_ID NAME                     LOGIN_ID
----------- ------------------------------ ----------
          1 Stefan Lindblad                STEFAN
          2 Nils Nilsson                   NISSE
          3 Scott King                     SCOTT
          4 John Smith                     JOHN
          1 Klas Andersson                 KLAS
          2 Eva Johansson                  EVA
          3 Joel Davids                    JOEL
          4 Clark Kent                     CLARK
 
8 rows selected.
Решение состоит в том, что к таблице CUSTOMER_TAB нужно подключить детальный контроль доступа. Это позволит показывать только те строки, которые относятся к приложению конкретного узла базы данных. Нужно создать еще одну таблицу APPLICATION_USERS, определяющую всех пользователей системы и старые узлы, в которых они работали. Это позволит также добавить новые функциональные возможности для менеджеров, использующих средства подготовки отчетов, которые могут иметь доступ ко вем строкам. Для этого таблица должна иметь следующий вид.
SQL> select * from application_users;
     USERNAME         FULL_NAME               APPLICATION_ID SEE_ALL
     -------------- --------------------- ---------------------------
     LEHNA          Lehna Sidestam                    1 N
     PETER          Peter Ericson                     1 Y
     JONAS          Jonas Rehborg                     2 N
     MICHAEL        Michael Johansson                 2 Y
 
Для выполнения задуманного мы начнем с создания одного контекста и обеспечим, чтобы каждому конечному пользователю во время соединения с базой данных в зависимости от его имени (USERNAME) назначалось два значения атрибутов APPLICATION_ID (идентификатор приложения) и SEE_ALL (смотреть все). В одном из предыдущих примеров мы также имели “само обслуживающиеся” функциональные возможности, когда пользователи могли видеть только свои собственные строки. Эти функциональные возможности отменены не будут. Контекстный пакет будет иметь примерно следующий вид:
SQL> create or replace package invoice_conpack
  2  is
  3   procedure set_custno;
  4  end;
  5  /
 
Package created.
 
SQL> create or replace package body invoice_conpack
  2  is
  3  procedure set_custno is
  4   v_custno varchar2(100);
  5          v_application_id number;
  6          v_see_all        varchar2(10);
  7  begin
  8   select customer_id, application_id into V_custno, v_application_id
  9   from scott.customer_tab;
 10 
 11   dbms_session.set_context('invoice_context','custno',v_custno);
 12   dbms_session.set_context('invoice_context','application_id',v_application_id);
 13  exception
 14   when no_data_found then
 15    begin
 16                    select application_id, see_all
 17                    into v_application_id, v_see_all
 18      from scott.application_users
 19                 where username = SYS_CONTEXT('USERENV','session_user');
 20 
 21  dbms_session.set_context('invoice_context','application_id',v_application_id);
 22  dbms_session.set_context('invoice_context','see_all',v_see_all);
 23 exception
 24   when no_data_found then
 25     null;
 26                  end;
 27  end;
 28  end invoice_conpack;
 29  /
 
Package body created. 
Это позволяет гарантировать, что мы начинаем с проверки – вошел ли в систему один из наших заказчиков, если в систему вошел не заказчик, проверим имя конечного пользователя и назначим ему соответствующий идентификатор приложения.
 
Сейчас наступило время настроить функции политики безопасности, чтобы она также “заботилась” о новом приложении. Новые функции политики безопасности будут выглядеть примерно так:
SQL> create or replace package invoice_polpack
  2  is
  3  function custno(d1 varchar2, d2 varchar2) return varchar2;
  4  function log_id(d1 varchar2, d2 varchar2) return varchar2;
  5  end;
  6  /
 
Package created.
 
SQL> create or replace package body invoice_polpack is
  2  function custno (d1 varchar2, d2 varchar2) return varchar2 is
  3      d_predicate varchar2(2000);
  4      v_see_all varchar2(10);
  5      v_application_id number;
  6  begin
  7      select sys_context('invoice_context','see_all'),
  8             sys_context('invoice_context','application_id')
  9      into   v_see_all,
 10             v_application_id
 11      from dual;
 12 
 13      if user = 'SCOTT' OR v_see_all = 'Y' then
 14          d_predicate := '1=1';
 15      elsif v_see_all ='N' and v_application_id is not null then
 16          d_predicate := 'application_id = sys_context(''invoice_context'',''application_id'')';
 17      else
 18          d_predicate := 'CUSTOMER_ID = sys_context(''invoice_context'',''custno'') AND Application_id = sys_context(''invoice_context'',''application_id'')';
 19      end if;
 20 
 21      return d_predicate;
 22  end custno;
 23  function log_id (d1 varchar2, d2 varchar2) return varchar2 is
 24   d_predicate varchar2(2000);
 25          v_see_all varchar2(10);
 26          v_application_id number;
 27  begin
 28      select sys_context('invoice_context','see_all'),
 29             sys_context('invoice_context','application_id')
 30      into   v_see_all,
 31             v_application_id
 32      from dual;
 33  
 34      if user = 'SCOTT' OR v_see_all = 'Y' then
 35          d_predicate := '1=1';
 36      elsif v_see_all = 'N' and v_application_id is not null then
 37          d_predicate := 'application_id = sys_context(''invoice_context'',''application_id'')';
 38      else   
 39   d_predicate := 'LOGIN_ID = SYS_CONTEXT(''USERENV'',''session_user'')';
 40      end if;
 41      return d_predicate;
 42  end log_id;
 43  end invoice_polpack;
 44  /
 
Package body created. 

После того, как это сделано, нам осталось только добавить (прикрепить) политику не к представлениям, а к таблицам с именами *_TAB. Это нужно сделать, поскольку представления не содержат всех столбцов. Они содержат ту информацию, которая была в старых приложениях перед началом миграции.

SQL> begin

  2     dbms_rls.add_policy('scott',
  3                         'invoice_tab',
  4                         'invoice_policy',
  5                         'scott',
  6                         'invoice_polpack.custno',
  7                         'select');
  8 
  9     dbms_rls.add_policy('scott',
 10                         'customer_tab',
 11                         'customer_policy',
 12                         'scott',
 13                         'invoice_polpack.log_id',
 14                         'select');
 15  end;
 16  /
 
PL/SQL procedure successfully completed.
 
Итак, когда пользователь JOEL входит в систему как постоянный заказчик, он будет видеть в таблицах только свои собственные строки, как это было и раньше:  
SQL> select * from scott.customer;
 
CUSTOMER_ID NAME                           LOGIN_ID
----------- ------------------------------ ----------
          3 Joel Davids                    JOEL
 
SQL> select * from scott.invoice;
 
    INV_ID     AMOUNT CUSTOMER_ID
---------- ---------- -----------
         2        600           3
         9       4500           3
        15      10500           3
        18       5700           3
        20       5900           3 
А когда в систему входит пользователь LEHNA, она будет конечным пользователем, который видит только данные первого приложения, как это было и раньше. Поскольку она является постоянным пользователем, она может видеть все строки, относящиеся к первому приложению:
SQL> select * from scott.customer;
 
CUSTOMER_ID NAME                           LOGIN_ID
----------- ------------------------------ ----------
          1 Stefan Lindblad                STEFAN
          2 Nils Nilsson                   NISSE
          3 Scott King                     SCOTT
          4 John Smith                     JOHN
 
SQL> select * from scott.invoice;
 
CUSTOMER_ID NAME                           LOGIN_ID
----------- ------------------------------ ----------
          1 Stefan Lindblad                STEFAN
          2 Nils Nilsson                   NISSE
          3 Scott King                     SCOTT
          4 John Smith                     JOHN
 
20 rows selected.
Пришло время показать пользователя, который извлечет пользу из новой структуры. Пользователь PETER – менеджер, который хочет видеть в приложении все. Для этого он будет использовать инструментальные средства конечных пользователей, такие, как Oracle Discoverer, настроенные на доступ непосредственно к базовым таблицам. Он будет видеть примерно следующее:  
SQL> select * from scott.customer_tab;
       CUSTOMER_ID APPLICATION_ID NAME                            LOGIN_ID
----------- -------------- ------------------------------ ----------
          1              1 Stefan Lindblad                STEFAN
          2              1 Nils Nilsson                   NISSE
          3              1 Scott King                     SCOTT
          4              1 John Smith                     JOHN
          1              2 Klas Andersson                 KLAS
          2              2 Eva Johansson                  EVA
          3              2 Joel Davids                    JOEL
          4              2 Clark Kent                     CLARK
 
8 rows selected.
 
SQL> select * from scott.invoice_tab;
 
    INV_ID APPLICATION_ID     AMOUNT CUSTOMER_ID
---------- -------------- ---------- -----------
         1              1        500           1
         2              1        600           2
                 .
                 .
        19              2       5800           1
        20              2       5900           3
 
40 rows selected.
В настоящее время мы трансформировали одно приложение, которое до этого размещалось в разных базах в разных узлах, в одну базу данных в одном узле. Это было сделано без каких-либо изменений данного клиентского приложения.
 
Заключение
 
Виртуальные частные базы данных с детальным контролем доступа и защищенными контекстами приложений дают возможность обеспечить в организациях защиту данных в сервере Oracle9i. Они гарантируют, что, независимо от того, как пользователи получают доступ к данным (через приложение, генератор отчетов или SQL*Plus), принудительно будет поддерживаться одна и та же политика управления доступом. Виртуальные частные базы данных в приложениях управления трудовыми ресурсами могут способствовать реализации сложных правил доступа к записям служащих. Виртуальные частные базы данных также дают возможность снизить стоимость разработки – средства обеспечения безопасности разрабатываются один раз в сервере данных, а не в каждом приложении, которое обращается к данным.

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

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Обсудить на форуме Oracle
Отправить ссылку на страницу по e-mail


Interface Ltd.
Тel/Fax: +7(095) 105-0049 (многоканальный)
Отправить E-Mail
http://www.interface.ru
Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 17.01.02