Oracle Label Security

Oracle Label Security (OLS) เป็นส่วนขยายของเทคโนโลยี Virtual Private Database (VPD) ซึ่งเริ่มนำมาใช้ตั้งแต่ Oracle 8i  OLS อนุญาตให้มีการควบคุมการเข้าถึงลงในแถวต่างๆ ตามป้ายกำกับที่ระบุ ฟังก์ชันการทำงานที่คล้ายคลึงกันสามารถทำซ้ำโดยใช้ Fine Grained Access Control (FGAC) แต่ OLS ให้โซลูชันที่ง่ายกว่าสำหรับการรักษาความปลอดภัยระดับแถว (row-level security) ในบทความนี้ฉันจะนำเสนอตัวอย่างง่ายๆของการกำหนดค่า OLS

ตั้งค่าฐานข้อมูล

  • หากไม่ได้เลือกตัวเลือก Label Security เมื่อครั้งติดตั้ง Oracle Database สามารถเรียกตัวติดตั้งและเลือกตัวเลือก Label Security เพิ่มเติมได้ภายหลัง
  • เข้าระบบด้วยบัญชีผู้ใช้ Oracle เปิด terminal พิมพ์ dbca (Database Server เป็น Linux)
  • เมื่อได้ Welcome Screen คลิก Next
  • ที่หน้า Operation คลิก Configure Database Options แล้วคลิก Next
  • หน้า Database เลือกฐานข้อมูลที่ต้องการ คลิก Next
  • ที่หน้า Database Features คลิกเลือก Label Security คลิก Next
  • คลิก Finish
  • เมื่อจบการตั้งค่าให้ restart database

สร้างผู้ใช้ทดสอบ

คำสั่งทั้งหมดทำภายใน sqlplus สร้างผู้ใช้ ols_test มีรหัสผ่านว่า password โดยให้สิทธิ์ CONNECT, RESOURCE, SELECT_CATALOG_ROLE

sqlplus, / as sysdba
CONN / AS SYSDBA

CREATE USER ols_test IDENTIFIED BY password 
DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp
GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO ols_test;

ต่อไปเป็นการให้สิทธิ์ในแพ็คเกจ OLS แก่ผู้ใช้ ols_test จำเป็นต้อง unlock ผู้ใช้ lbacsys และตั้งรหัสผ่านว่า lbacsys เพื่อใช้เป็นคนกำหนดสิทธิ์ต่างๆ ให้ ols_test ได้แก่สิทธิ์ execute บน sa_components, sa_user_admin, sa_label_admin, sa_policy_admin, sa_audit_admin, sa_sysdba, to_lbac_data_label และให้ ols_test เป็น lbac_dba

sqlplus, / as sysdba, lbacsys/lbacsys
ALTER USER lbacsys IDENTIFIED BY lbacsys ACCOUNT UNLOCK;

CONN lbacsys/lbacsys

GRANT EXECUTE ON sa_components TO ols_test WITH GRANT OPTION;
GRANT EXECUTE ON sa_user_admin TO ols_test WITH GRANT OPTION;
GRANT EXECUTE ON sa_user_admin TO ols_test WITH GRANT OPTION;
GRANT EXECUTE ON sa_label_admin TO ols_test WITH GRANT OPTION;
GRANT EXECUTE ON sa_policy_admin TO ols_test WITH GRANT OPTION;
GRANT EXECUTE ON sa_audit_admin  TO ols_test WITH GRANT OPTION;

GRANT LBAC_DBA TO ols_test;
GRANT EXECUTE ON sa_sysdba TO ols_test;
GRANT EXECUTE ON to_lbac_data_label TO ols_test;

สร้าง Policy

ต่อไปจะสร้าง policy ชื่อ region_policy ด้วยผู้ใช้ ols_test และระบุชื่อของ column ที่จะเป็นที่เก็บ label ว่า region_label

sqlplus, ols_test/password
CONN ols_test/password

BEGIN
	SA_SYSDBA.CREATE_POLICY(
	policy_name => 'region_policy',
	column_name => 'region_label');
END;
/

GRANT region_policy_DBA TO ols_test;

กำหนด component ของ label

สร้าง component ของ label เพื่อใช้สำหรับ policy ที่สร้างไว้ตอนต้น region_policy
– สร้างระดับไว้ 3 ระดับ คือ 20, 40 และ 60 มีชื่อเรียกสั้น ๆ ว่า L1, L2 และ L3 ชื่อเรียกยาว ๆ ว่า Level 1, Level 2 และ Level 3 ตามลำดับ
– สร้างสิทธิ์การใช้งานไว้ 2 ชนิดประกอบด้วย 100, 120 มีชื่อเรียกอย่างย่อว่า M และ E และชื่อเรียกยาวว่า Manage และ Employee ตามลำดับ
– สร้างกลุ่มของ policy ไว้ 4 กลุ่ม 20, 40, 60 และ 80 ชื่อย่อ R20, R40, R60 และ R80 ชื่อยาว Region North, Region South, Region East และ Region West ตามลำดับ
สุดท้ายกำหนดให้ ols_test เป็นผู้มีสิทธิ์สูงสุดใน policy region_policy

sqlplus, ols_test/password
EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',20,'L1','Level 1');
EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',40,'L2','Level 2');
EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',60,'L3','Level 3');

EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('region_policy',100,'M','MANAGEMENT');
EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('region_policy',120,'E','EMPLOYEE');

EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',20,'R20','REGION NORTH');
EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',40,'R40','REGION SOUTH');
EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',60,'R60','REGION EAST');
EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',80,'R80','REGION WEST');

EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('region_policy','ols_test','FULL,PROFILE_ACCESS');

สร้าง Table ทดสอบ

สร้าง table พร้อมข้อมูลทดสอบใน schema ols_test โดย table ชื่อ customers มีฟิลด์ id, cust_type, first_name, last_name, region, credit กำหนดให้ id เป็น Primary key และ insert ข้อมูลลง table ด้วย

sqlplus, ols_test/password
CONN ols_test/password

CREATE TABLE customers (
	id                  NUMBER(10) NOT NULL,
	cust_type           VARCHAR2(10),
	first_name          VARCHAR2(30),
	last_name           VARCHAR2(30),
	region              VARCHAR2(5),
	credit              NUMBER(10,2),
	CONSTRAINT customer_pk PRIMARY KEY (id));

GRANT SELECT, INSERT, UPDATE, DELETE ON customers TO PUBLIC;

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;

สร้าง label function

เป็นการสร้าง function ชื่อ get_customer_label สำหรับสร้าง label ประกอบด้วย p_cust_type, p_region, p_credit
– โดยกำหนด policy ระดับด้วย p_credit >2000 ก็จะมี v_label ว่า L3 ถ้า p_credit > 500 v_label คือ L2 และ p_credit < 500 v_label คือ L1
– กำหนด p_cust_type เป็น platinum หรือไม่ถ้าเป็นก็จะอยู่ในจะมีิสิทธิ์ M ถ้าไม่ก็จะเป็น E โดยเอาค่าที่ได้มาต่อกับ v_label ข้อที่แล้ว
– กำหนด p_region ถ้าเป็น north จะอยู่กลุ่ม R20 เป็นต้น และจะเอาค่าที่ได้ไปต่อกับ v_label ที่ได้จากข้อที่แล้ว
– ค่าที่ return จา function นี้จะเป็นชื่อ policy และ v_label สุดท้ายที่ได้จากข้อกำหนดที่กล่าวมาข้างต้น

sqlplus, ols_test/password
CREATE OR REPLACE FUNCTION get_customer_label (
	p_cust_type  IN  VARCHAR2,
	p_region     IN  VARCHAR2,
	p_credit     IN  NUMBER)
RETURN LBACSYS.LBAC_LABEL AS
	v_label  VARCHAR2(80);
BEGIN
	IF p_credit > 2000 THEN
		v_label := 'L3:';
	ELSIF p_credit > 500 THEN
		v_label := 'L2:';
	ELSE
		v_label := 'L1:';
	END IF;

	IF p_cust_type = 'PLATINUM' THEN
		v_label := v_label || 'M:';
	ELSE
		v_label := v_label || 'E:';
	END IF;
	IF p_region = 'NORTH' THEN
		v_label := v_label || 'R20';
	ELSIF p_region = 'SOUTH' THEN
		v_label := v_label || 'R40';
	ELSIF p_region = 'EAST' THEN
		v_label := v_label || 'R60';
	ELSIF p_region = 'WEST' THEN
		v_label := v_label || 'R80';
	END IF;

	RETURN TO_LBAC_DATA_LABEL('region_policy',v_label);
END get_customer_label;
/

SHOW ERRORS

สั่งให้ Policy ทำงานกับ table ที่สร้าง

เมื่อสั่งให้ Policy ทำงานจะเป็นการเพิ่ม column ที่เก็บ label ใน table เป้าหมาย

sqlplus, ols_test/password
CONN ols_test/password

BEGIN
	SA_POLICY_ADMIN.APPLY_TABLE_POLICY(
	policy_name   => 'REGION_POLICY',
	schema_name   => 'OLS_TEST',
	table_name    => 'CUSTOMERS',
	table_options => 'NO_CONTROL');
END;
/

เริ่มสร้าง label

เป็นการกำหนดค่าเริ่มต้นสำหรับ region_label ลงไปใน table ซึ่งถ้าไม่มีข้อมูลในฟิลด์นี้จะไม่มีใครสามารถเข้าถึงได้

sqlplus, ols_test/password
UPDATE customers
SET region_label = CHAR_TO_LABEL('REGION_POLICY','L1');

COMMIT;

สั่งให้ Policy ทำงานอีกครั้ง

ต่อไปจะเป็นการสั่งให้ policy ทำงานอีกครั้งใน table customers เพื่อเปลี่ยนค่าเป็นค่าที่ได้จะเป็นค่าจาก function ที่สร้างไว้

sqlplus, ols_test/password
BEGIN
	SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('REGION_POLICY','OLS_TEST','CUSTOMERS');
	SA_POLICY_ADMIN.APPLY_TABLE_POLICY (
	policy_name => 'REGION_POLICY',
	schema_name => 'OLS_TEST',
	table_name  => 'CUSTOMERS',
	table_options => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL',
	label_function => 'ols_test.get_customer_label(:new.cust_type,:new.region,:new.credit)',
	predicate => NULL);
END;
/

สั่งให้ label ทำงานกับข้อมูลในแต่ละแถว

ปรับปรุงข้อมูลให้เป็นตามฟังก์ชันที่สร้างไว้กับข้อมูลแต่ละแถว

sqlplus, ols_test/password
UPDATE customers
SET    first_name = first_name;

COMMIT;

สร้าง user ทดสอบ

สร้าง user อื่นๆ เพื่อทดสอบ label ได้แก่ sales_manager, sales_north, sales_south, sales_east, sales_west
– sales_manager มี label ว่า L3:M,E:R20,R40,R60,R80 แปลว่า sales_manager สามารถอ่านและเขียนข้อมูลได้ทุก Region
– sales_north มี label ว่า L3:E:R20,R40 แปลว่า sales_north สามารถอ่านข้อมูลที่อยู่ใน Region North และ South
– sales_south มี label ว่า L3:E:R20,R40,R60,R80 แปลว่า sales_south อ่านข้อมูลได้ทุก Region
– sales_east มี label ว่า L3:E:R60 แปลว่า sales_east อ่านข้อมูล Region East ได้อย่างเดียว
– sales_west มี label ว่า L3:E:R80 แปลว่า sales_west อ่านข้อมูล Region West ได้อย่างเดียว

sqlplus, / as sysdba, (sales_manager, sales_nort, sales_south, sales_east, sales_west, ols_test)/password
CONN / AS SYSDBA;

CREATE USER sales_manager IDENTIFIED BY password;
CREATE USER sales_north IDENTIFIED BY password;
CREATE USER sales_south IDENTIFIED BY password;
CREATE USER sales_east IDENTIFIED BY password;
CREATE USER sales_west IDENTIFIED BY password;

GRANT CONNECT TO sales_manager, sales_north, sales_south, sales_east, sales_west;

CONN ols_test/password

BEGIN
	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_manager','L3:M,E:R20,R40,R60,R80');
	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_north','L3:E:R20,R40');
	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_south','L3:E:R20,R40,R60,R80');
	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_east','L3:E:R60');
	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_west','L3:E:R80');
END;
/

ทดสอบ Label Security 

เข้าระบบผ่าน sqlplus ด้วย user ต่างๆ ที่สร้างในข้อที่แล้วเพื่อดูข้อมูลว่าถูกต้องหรือไม่ เพื่อความสะดวกจึงเข้าผ่านโปรแกรมสำเร็จรูปอื่นเพื่อให้ดูง่าย ได้ผลดังรูปต่อไปนี้นี้

sqlplus, sales_manager, sales_north, sales_south, sales_east, sales_west

จบขอให้สนุก

ที่มา https://oracle-base.com/articles/9i/oracle-label-security-9i#Installation