Oracle Label Security. Первое знакомство

в 19:56, , рубрики: oracle, security, Администрирование баз данных, информационная безопасность, метки: ,

Oracle Label Security (OLS) — это еще одна возможность разграничения доступа к данным в Oracle Database Server. Отличительной особенностью OLS является многоуровневость политик доступа и хранение атрибутов управления доступом вместе с данными.

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

Oracle Label Security является платной опцией Oracle Database Enterprise Edition.

Ниже будут рассмотрены основные понятия и приведен пример использования OLS.

Вводная часть

Oracle Label Security использует в своей работе Oracle Virtual Private Database (VPD), но в отличии от VPD не требует написания PL/SQL кода. Управлять всеми аспектами OLS можно как с помощью PL/SQL пакетов, так и посредством Oracle Enterprise Manager.

В статье будет рассмотрена реализация OLS для версии Oracle Databse 12c, с отличиями от предыдущих версий можно ознакомиться здесь.

Компоненты OLS

Labels (метки). Метки являются представлением атрибутов доступа к данным.
Метки состоят из следующих компонентов:

  • Levels (уровни). Представляются в виде числа от 0 до 9999. Чем больше число, тем выше уровень доступа.
  • Compartments (отделы). Необязательный линейный список, позволяющий более точно определить уровень доступа. Например: «Коммерческий отдел», «IT отдел» и т.д. В примере не используются.
  • Groups (группы). Иерархическая структура, если предоставлен доступ к вершине, то автоматически получается доступ к листьям. Например: Региональное деление, есть вершина — «все регионы» и листья — «Москва», «Лондон» и т.д. Если есть доступ к «все регионы», то есть доступ и к регионам «Москва» и «Лондон». Если есть доступ только к регионy «Москва», то доступ к остальным регионам закрыт.

Policy (политики). Связывают воедино метки, таблицы и авторизацию.

Постановка задачи

Имеется компания Z с региональной структурой.
В компании эксплуатируется система, в которую поступают данные о платежах клиентов. Поступают они из ERP и заносятся в таблицу PAYMENTS.
Требуется обеспечить разграничение доступа на чтение, по суммам платежей и по регионам. Данные об особо крупных платежах должны хранятся в отдельной партиции, на зашифрованном диске. При поступлении платежа из ERP ему должна быть присвоена метка с учетом суммы и региона. Запись в таблицу ограничивается стандартными механизмами oracle и возможнa только из ERP.

Суммы платежей разбиваем на 3 части:

  1. Big (большие) — от 10000
  2. Medium (средние) — от 5000 до 9999
  3. Small (мелкие) — до 5000

Регионы:

  1. MO (Москва и облать)
  2. NW (Северо-запад)

Пользователи:

  1. big_boss — имеет максимальный уровень доступа, видит все данные
  2. med_boss — видит платежи от 5000 до 9999 по всем регионам
  3. mo_big_boss — видит все платежи, но только в регионе MO

Реализация

Как включить опцию Oracle Label Security смотрим здесь.
Создаем таблицу в схеме TEST, в которую будут поступать платежи:

Скрытый текст
create table PAYMENTS (
  ID number,
  CNAME  varchar2(64),  /* Название компании плательщика */
  REGION char(2),  /* Аббревиатура региона MO/NW */
  AMOUNT number, /* Сумма платежа */
  ols_payments number(10), /* Служебное поле для хранения метки */
  CONSTRAINT "PAYMENTS_PK" PRIMARY KEY ("ID")
  )
  PARTITION BY RANGE (ols_payments) (
   PARTITION SP VALUES LESS THAN (80000),
   PARTITION MP VALUES LESS THAN (90000),
   PARTITION BP VALUES LESS THAN (MAXVALUE) /* В реальной системе эта партиция будет располагаться на шифрованном диске */
  );
grant select on payments to public;

Колонка ols_payments создана заранее, чтобы можно было сделать partitioning. Если этого не требуется, то она может быть создана автоматически, при применении policy.
Вся дальнейшая работа по настройке пойдет из под пользователя LBACSYS.
Для каждой policy создается специальная роль вида policy_DBA. Обладатель роли может изменять эту policy.

Создаем policy payments_pol:

Скрытый текст

EXEC SA_SYSDBA.CREATE_POLICY (
  policy_name      => 'payments_pol', /* Наименование policy */
  column_name      => 'ols_payments', /* Колонка таблицы для хранения меток */
  default_options  => 'read_control'); /* По умолчанию ограничиваем доступ на чтение */

Cоздаем уровни доступа по суммам для нашей policy:

Скрытый текст

BEGIN
 SA_COMPONENTS.CREATE_LEVEL (
   policy_name   => 'payments_pol',
   level_num     => 90,  /* Числовое значение */
   short_name    => 'B', /* Сокращенное наименование */
   long_name     => 'BIG_PAYMENT'); /* Полное наименование */

 SA_COMPONENTS.CREATE_LEVEL (
   policy_name   => 'payments_pol',
   level_num     => 80,
   short_name    => 'M',
   long_name     => 'MEDIUM_PAYMENT');

 SA_COMPONENTS.CREATE_LEVEL (
   policy_name   => 'payments_pol',
   level_num     => 70,
   short_name    => 'S',
   long_name     => 'SMALL_PAYMENT');
END;
/

Для каждого уровня необходимо указать его числовое заначение, сокращенное и полное наименование. Сокращенное наименование далее будет использоваться во всех ссылках.

Создаем группы по регионам:

Скрытый текст

BEGIN
  /* Корневая группа */
  SA_COMPONENTS.CREATE_GROUP (
   policy_name     => 'payments_pol',
   group_num       => 10,  /* Числовое заначение */
   short_name      => 'RG', /* Сокращенное наименование */
   long_name       => 'REGIONS'); /* Полное наименование */

  SA_COMPONENTS.CREATE_GROUP (
   policy_name     => 'payments_pol',
   group_num       => 20,
   short_name      => 'MO',
   long_name       => 'MOSCOW_REGION',
   parent_name     => 'RG'); /* родитель */

  SA_COMPONENTS.CREATE_GROUP (
   policy_name     => 'payments_pol',
   group_num       => 30,
   short_name      => 'NW',
   long_name       => 'NW_REGION',
   parent_name     => 'RG');
END;
/

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

Текстовый формат метки выглядит как «LEVEL:COMPARTMENT1,..,COMPARTMENTN:GROUP1,...,GROUPN».
Метка для записи содержащей сумму больше 10000 для московского региона будет выглядеть как «B::MO».

Для отображения текстовых меток в числовое значение создаются Label tags (тэги меток). Label tags могут быть сгенерированны автоматически или заданы вручную. Поскольку используется партиционирование по полю содержащему Label tags, создаем их вручную. Важно помнить что значения Label tags должны быть уникальны в рамках базы и не могут дублироваться в разных policy. Label tags никак не связаны ни с номерами групп, ни с номерами уровней.

Создаем тэги:

Скрытый текст

BEGIN
-- RG labels
  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 90010, /* Числовое передставление метки */
   label_value     => 'B::RG', /* Текстовое передставление метки */
   data_label      => TRUE);

  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 80010,
   label_value     => 'M::RG',
   data_label      => TRUE);

  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 70010,
   label_value     => 'S::RG',
   data_label      => TRUE);

-- MO LABELS
  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 90020,
   label_value     => 'B::MO',
   data_label      => TRUE);

  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 80020,
   label_value     => 'M::MO',
   data_label      => TRUE);

  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 70020,
   label_value     => 'S::MO',
   data_label      => TRUE);

-- NW LABELS
  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 90030,
   label_value     => 'B::NW',
   data_label      => TRUE);

  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 80030,
   label_value     => 'M::NW',
   data_label      => TRUE);

  SA_LABEL_ADMIN.CREATE_LABEL (
   policy_name     => 'payments_pol',
   label_tag       => 70030,
   label_value     => 'S::NW',
   data_label      => TRUE);
END;
/

Осталось написать функцию осуществляющую генерацию меток по данным:

Скрытый текст

create or replace function payments_label(region varchar2, amount number) return LBACSYS.LBAC_LABEL as 
  lvl varchar2(32);
  reg varchar2(32);
  rvalue number(10);
 begin
  case region
   when 'MO' then reg := 'MO';
   when 'NW' then reg := 'NW';
   else raise_application_error(-20000, 'invalid region.');
  end case;
  case 
   when amount >= 10000 then lvl := 'B';
   when amount >= 5000 then lvl := 'M';
   else lvl := 'S';
  end case;
   return LBACSYS.to_lbac_label('PAYMENTS_POL', lvl || '::' || reg);
end;

И можно применять нашу policy к таблице:

Скрытый текст

EXEC SA_POLICY_ADMIN.APPLY_TABLE_POLICY (
  policy_name    => 'payments_pol',
  schema_name    => 'test', 
  table_name     => 'payments',
  table_options  => 'READ_CONTROL,HIDE', /* контролировать чтение, не показывать служебную колонку */
  label_function => 'test.payments_label(:new.region,:new.amount)', /* функция генерации меток, вызов будет вставлен в автоматически созданные триггера на insert и update. Отсюда и названия параметров */
  predicate      => NULL);

Заполним таблицу тестовыми данными имитируя поступление платежей из ERP:

Скрытый текст

$ sqlplus test/test
insert into payments values(1, 'РОГА и КОПЫТА, Москва', 'MO', 100000);
insert into payments values(2, 'РОГА и КОПЫТА, Москва', 'MO', 7000);
insert into payments values(3, 'РОГА и КОПЫТА, Москва', 'MO', 100000);
insert into payments values(4, 'ВОДКА и БАЛАЛАЙКИ, Питер', 'NW', 150000);
insert into payments values(5, 'ВОДКА и БАЛАЛАЙКИ, Питер', 'NW', 3000);

И раздадим права пользователям:

Скрытый текст

-- big boss
BEGIN
 SA_USER_ADMIN.SET_LEVELS (
  policy_name   => 'payments_pol',
  user_name     => 'big_boss', 
  max_level     => 'B');

 SA_USER_ADMIN.SET_GROUPS (
  policy_name   => 'payments_pol',
  user_name     => 'big_boss', 
  read_groups   => 'RG');

-- medium boss
 SA_USER_ADMIN.SET_LEVELS (
  policy_name   => 'payments_pol',
  user_name     => 'med_boss', 
  max_level     => 'M');

 SA_USER_ADMIN.SET_GROUPS (
  policy_name   => 'payments_pol',
  user_name     => 'med_boss', 
  read_groups   => 'RG');

-- big boss of MO region
 SA_USER_ADMIN.SET_LEVELS (
  policy_name   => 'payments_pol',
  user_name     => 'mo_big_boss', 
  max_level     => 'B');

 SA_USER_ADMIN.SET_GROUPS (
  policy_name   => 'payments_pol',
  user_name     => 'mo_big_boss', 
  read_groups   => 'MO');
END;
/

Ну и теперь проверим что получилось:

Убеждаемся что big_boss видит все записи:

$ sqlplus big_boss/qw
SQL> select label_to_char (ols_payments) label, id, cname, amount from test.payments;

LABEL		   ID CNAME				 AMOUNT
---------- ---------- ------------------------------ ----------
S::MO               3 РОГА и КОПЫТА, Москва                2000
S::NW               5 ВОДКА и БАЛАЛАЙКИ, Питер             3000
M::MO               2 РОГА и КОПЫТА, Москва                7000
B::MO               1 РОГА и КОПЫТА, Москва              100000
B::NW               4 ВОДКА и БАЛАЛАЙКИ, Питер           150000

Убеждаемся что med_boss видит записи с суммой менее 10000 по всем регионам:

sqlplus med_boss/qw
SQL> select label_to_char (ols_payments) label, id, cname, amount from test.payments;

LABEL		   ID CNAME				 AMOUNT
---------- ---------- ------------------------------ ----------
S::MO               3 РОГА и КОПЫТА, Москва                2000
S::NW               5 ВОДКА и БАЛАЛАЙКИ, Питер             3000
M::MO               2 РОГА и КОПЫТА, Москва                7000

Убеждаемся что mo_big_boss видит записи с любыми суммами но только в московском регионе:

$ sqlplus mo_big_boss/qw
SQL> select label_to_char (ols_payments) label, id, cname, amount from test.payments;

LABEL		   ID CNAME				 AMOUNT
---------- ---------- ------------------------------ ----------
S::MO               3 РОГА и КОПЫТА, Москва                2000
M::MO               2 РОГА и КОПЫТА, Москва                7000
B::MO               1 РОГА и КОПЫТА, Москва              100000

PS. Oracle Label Security поддерживает разграничение доступа и для INSERT/DELETE/UPDATE, но размер статьи не позволяет рассказать обо всем. Документация доступна здесь.

Автор: xlix123

Источник

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


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js