暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

利用Oracle Lable Security实现行级安全性

OCM之家 2021-08-19
1877

作者介绍:

李成伟,OCM之家核心成员,获得Oracle 11g OCP和OCM认证,金融保险行业资深Oracle DBA,精通Oracle数据库各项技能,尤其擅长实施部署安装,DG和RAC。


一、前言
在Oracle9i中有一个组件称为Oracle Label Security,这个组件实现了基于自定义策略而对数据库中的表甚或是整个Schema提供行级安全性功能。实际上Oracle Label Security是Oracle8.1.7中提出的,在9i版本中功能得到了大幅度增强。  

本文通过一个简单的例子对Oracle Label Security的功能作初步的探讨,本文使用的环境是Oracle Database 11g Enterprise Edition Release 11.2.0.3 for linux 32 bit。


二、流程:

首先我们了解一下实现Oracle Label Security的大体流程。 通过Oracle提供的一系列存储过程,先创建一个policy,然后在policy中创建level,compartment,group,之后通过这些定义好的level,compartment,group再定义label,然后将policy绑定到某张表或者某个schema,最后再给相应的用户设置label。  


其中牵涉到几个名词,解释一下: 

Policy:就是安全策略,一个安全策略是level,compartment,group,label的集合。 

Level:等级,这是最基础的安全控制等级,必须设置。Compartment:分隔,提供第二级的安全控制,是可选的。 

Group:组,提供第三级的安全控制,是可选的。

Label:标签,最终体现到每一行上的安全标签,必须设置。只有用户被赋予的标签和此行上的标签相同或者等级更高的时候,该行才能够被用户存取。


三、实验步骤:

1
安装

Oracle Label Security仅适用于企业版的许可选项。在安装数据库软件的时候必须保证选择了Oracle Label Security组件,否则所有功能都无法使用。如果当时没有选择,可以重新运行Universal Installer进行安装。在11.2.0的企业版中Oracle Label Security组件已经自动被安装了。通过chopt命令来启动或者关闭Oracle Label Security组件。

开启OLS: 

关闭OLS:

Oracle Label Security相关的用户可以利用$ORACLE_HOME/rdbms/admin/catols.sql创建。

SYS@PROD1>@?/rdbms/admin/catols.sql

在这个脚本的最后会自动关闭数据库,所以请不要在生产库上直接测试。

再次打开数据库,就可以使用LBACSYS用户登录了,默认密码就是lbacsys,如果投放在生产环境中,请立刻修改默认密码。


2
创建测试用户并赋予相关权限

SYS@PROD1>CREATE USER ols_test IDENTIFIED BY ols_test DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp;

User created.

SYS@PROD1>GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO ols_test;

Grant succeeded.

SYS@PROD1>ALTER USER lbacsys IDENTIFIED BY lbacsys ACCOUNT UNLOCK;

User altered.

SYS@PROD1>CONN lbacsys/lbacsys

Connected.

LBACSYS@PROD1>GRANT EXECUTE ON sa_components TO ols_test WITH GRANT OPTION;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON sa_user_admin TO ols_test WITH GRANT OPTION;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON sa_user_admin TO ols_test WITH GRANT OPTION;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON sa_label_admin TO ols_test WITH GRANT OPTION;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON sa_policy_admin TO ols_test WITH GRANT OPTION;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON sa_audit_admin  TO ols_test WITH GRANT OPTION;

Grant succeeded.

LBACSYS@PROD1>GRANT LBAC_DBA TO ols_test;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON sa_sysdba TO ols_test;

Grant succeeded.

LBACSYS@PROD1>GRANT EXECUTE ON to_lbac_data_label TO ols_test;

Grant succeeded.


3
创建Policy

SYS@PROD1>conn ols_test/ols_test 

Connected.

OLS_TEST@PROD1>begin

  2  SA_SYSDBA.CREATE_POLICY(

  3  policy_name => 'region_policy',

  4  column_name => 'region_label');

  5  END;

  6  /

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>GRANT region_policy_DBA TO ols_test;

Grant succeeded.


4
定义Labels的内容

(1)定义Levels

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',20,'L1','Level 1');

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',40,'L2','Level 2');

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',60,'L3','Level 3');

PL/SQL procedure successfully completed.


第一个参数是上一步创建的安全策略的名字。第二个参数是Level的等级,数字越大表示权限越高,比如此处具有L3等级的就可以同时查看有L2和L1等级的数据。第三个参数是Level的短名,随便定义。第四个参数是Level的长名,只是起到一个说明的作用,随便定义。


可以从DBA_SA_LEVELS视图中查询安全等级的情况。


(2)定义Compartments

本步操作是可选项,仅仅使用上一步中的Level就已经可以控制数据的行级安全性了,但是如果要实现更加复杂的控制,就可能需要定义Compartment和下一步的Group。

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('region_policy',100,'M','MANAGEMENT');

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('region_policy',120,'E','EMPLOYEE');

PL/SQL procedure successfully completed.

参数依次是安全策略名,Compartment数字,短名,长名,此处的Compartment数字不涉及到权限的高低,仅仅是一个标识符而已。

可以从DBA_SA_COMPARTMENTS视图中查询安全间隔的情况。


(3)定义Groups

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',20,'R20','REGION NORTH');

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',40,'R40','REGION SOUTH');

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',60,'R60','REGION EAST');

PL/SQL procedure successfully completed.

OLS_TEST@PROD1>EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',80,'R80','REGION WEST');

PL/SQL procedure successfully completed.

参数依次是安全策略名,Group数字,短名,长名,此处的Group数字不涉及到权限的高低,仅仅是一个标识符而已。

可以从DBA_SA_GROUPS视图中查询安全组的情况。

注意,create_group存储过程有第5个参数,是parent_name,通过这个参数可以实现几乎无限制的多层权限控制,这里就不再深入了。


(4)设置用户权限

OLS_TEST@PROD1>EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('region_policy','ols_test','FULL,PROFILE_ACCESS');

PL/SQL procedure successfully completed.


5
创建测试的schema

OLS_TEST@PROD1>CREATE TABLE customers (

 2  id                            NUMBER(10) NOT NULL,

 3  cust_type                VARCHAR2(10),

 4  first_name               VARCHAR2(30),

 5  last_name                VARCHAR2(30),

 6  region                      VARCHAR2(5),

 7  credit                       NUMBER(10,2),

 8  CONSTRAINT customer_pk PRIMARYKEY (id));

Table created.

OLS_TEST@PROD1>GRANT SELECT, INSERT, UPDATE, DELETE ON customers TO PUBLIC;

Grant succeeded.


编辑插入脚本并插入

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 1, 'SILVER', 'Harry', 'Hill', 'NORTH', 11000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 2, 'SILVER', 'Vic', 'Reeves', 'NORTH', 2000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 3, 'SILVER', 'Bob', 'Mortimer', 'WEST', 500.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 4, 'SILVER', 'Paul', 'Whitehouse', 'SOUTH', 1000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 5, 'SILVER', 'Harry', 'Enfield', 'EAST', 20000.00);


INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 6, 'GOLD', 'Jenifer', 'Lopez', 'WEST', 500.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 7, 'GOLD', 'Kylie', 'Minogue', 'NORTH', 1000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 8, 'GOLD', 'Maria', 'Carey', 'WEST', 1000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES ( 9, 'GOLD', 'Dani', 'Minogue', 'SOUTH', 20000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES (10, 'GOLD', 'Whitney', 'Houston', 'EAST', 500.00);


INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES (11, 'PLATINUM', 'Robbie', 'Williams', 'SOUTH', 500.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES (12, 'PLATINUM', 'Thom', 'Yorke', 'NORTH', 2000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES (13, 'PLATINUM', 'Gareth', 'Gates', 'WEST', 10000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES (14, 'PLATINUM', 'Darius', 'Dinesh', 'EAST', 2000.00);

INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)

  VALUES (15, 'PLATINUM', 'Will', 'Young', 'EAST', 100.00);

COMMIT;


6
创建labels

这里是手工编辑的一个函数来创建labels

OLS_TEST@PROD1>CREATE OR REPLACE FUNCTION get_customer_label (

  2  p_cust_type  IN  VARCHAR2,

  3  p_region     IN  VARCHAR2,

  4  p_credit     IN  NUMBER)

  5  RETURN LBACSYS.LBAC_LABEL AS

  6  v_label  VARCHAR2(80);

  7  BEGIN

  8  IF p_credit > 2000 THEN

  9  v_label := 'L3:';

 10  ELSIF p_credit > 500 THEN

 11  v_label := 'L2:';

 12  ELSE

 13  v_label := 'L1:';

 14  END IF;

 15  

 16  IF p_cust_type = 'PLATINUM' THEN

 17  v_label := v_label || 'M:';

 18  ELSE

 19  v_label := v_label || 'E:';

 20  END IF;

 21  

 22  IF p_region = 'NORTH' THEN

 23  v_label := v_label || 'R20';

 24  ELSIF p_region = 'SOUTH' THEN

 25  v_label := v_label || 'R40';

 26  ELSIF p_region = 'EAST' THEN

 27  v_label := v_label || 'R60';

 28  ELSIF p_region = 'WEST' THEN

 29  v_label := v_label || 'R80';

 30  END IF;

 31  

 32  RETURN TO_LBAC_DATA_LABEL('region_policy',v_label);

 33  END get_customer_label;

 34  /

Function created.

OLS_TEST@PROD1>show errors

No errors.


7
将策略赋予表

OLS_TEST@PROD1>BEGIN

  2  SA_POLICY_ADMIN.APPLY_TABLE_POLICY(

  3  policy_name   => 'REGION_POLICY',

  4  schema_name   => 'OLS_TEST',

  5  table_name    => 'CUSTOMERS',

  6  table_options => 'NO_CONTROL');

  7  END;

  8  /

PL/SQL procedure successfully completed.


8
初始化标签

接下来,我们初始化现有数据的标签列。 没有这个权限将不允许访问。

OLS_TEST@PROD1>UPDATE customers

2  SET region_label = CHAR_TO_LABEL('REGION_POLICY','L1');

15 rows updated.

OLS_TEST@PROD1>commit;

Commit complete.


9
重新应用策略

接下来,我们将策略重新应用到表并链接到刚才创建的label function。

OLS_TEST@PROD1>BEGIN

  2  SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('REGION_POLICY','OLS_TEST','CUSTOMERS');

  3  SA_POLICY_ADMIN.APPLY_TABLE_POLICY (

  4  policy_name => 'REGION_POLICY',

  5  schema_name => 'OLS_TEST',

  6  table_name  => 'CUSTOMERS',

  7  table_options => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL',

  8  label_function =>'ols_test.get_customer_label(:new.cust_type,:new.region,:new.credit)',

  9  predicate => NULL);

 10  END;

 11  /

PL/SQL procedure successfully completed.


10
重新标记行

接下来,我们使用label function重新标记行。

OLS_TEST@PROD1>UPDATE customers set first_name = first_name;

15 rows updated.

OLS_TEST@PROD1>commit;

Commit complete.


11
创建用户来测试安全设置

OLS_TEST@PROD1>conn as sysdba

Connected.

SYS@PROD1>CREATE USER sales_manager IDENTIFIED BY sales_manager;

User created.

SYS@PROD1>CREATE USER sales_north IDENTIFIED BY sales_north;

User created.

SYS@PROD1>CREATE USER sales_south IDENTIFIED BY sales_south;

User created.

SYS@PROD1>CREATE USER sales_east IDENTIFIED BY sales_east;

User created.

SYS@PROD1>CREATE USER sales_west IDENTIFIED BY sales_west;

User created.

SYS@PROD1>GRANT CONNECT TO sales_manager, sales_north, sales_south, sales_east, sales_west;

Grant succeeded.

SYS@PROD1>conn ols_test/ols_test

Connected.

OLS_TEST@PROD1>BEGIN

  2 SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_manager','L3:M,E:R20,R40,R60,R80');

  3  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_north','L3:E:R20,R40');

  4  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_south','L3:E:R20,R40,R60,R80');

  5  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_east','L3:E:R60');

  6  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_west','L3:E:R80');

  7  END;

  8  /

PL/SQL procedure successfully completed.


12
测试Label Security Policy

OLS_TEST@PROD1>conn as sysdba

Connected.

SYS@PROD1>CREATE USER sales_manager IDENTIFIED BY sales_manager;

User created.

SYS@PROD1>CREATE USER sales_north IDENTIFIED BY sales_north;

User created.

SYS@PROD1>CREATE USER sales_south IDENTIFIED BY sales_south;

User created.

SYS@PROD1>CREATE USER sales_east IDENTIFIED BY sales_east;

User created.

SYS@PROD1>CREATE USER sales_west IDENTIFIED BY sales_west;

User created.

SYS@PROD1>GRANT CONNECT TO sales_manager, sales_north, sales_south, sales_east, sales_west;

Grant succeeded.

SYS@PROD1>conn ols_test/ols_test

Connected.

OLS_TEST@PROD1>BEGIN

  2 SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_manager','L3:M,E:R20,R40,R60,R80');

  3  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_north','L3:E:R20,R40');

  4  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_south','L3:E:R20,R40,R60,R80');

  5  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_east','L3:E:R60');

  6  SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_west','L3:E:R80');

  7  END;

  8  /

PL/SQL procedure successfully completed.

近期精彩文件推荐

数据迁移之ASM迁移至本地实现方法

一次不可思议需求的数据迁移

ORACLE 10.2.0.5 RAC升级到11.2.0.3

一次有趣的性能诊断

11gR2添加DG单节点操作记录



中国OCM之家

专注数据    共现梦想

QQ群:554334183


文章转载自OCM之家,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论