OracleLabelSecurity(Oracle標籤安全性)

cnbird發表於2013-04-17

作者:Darl Kuhn、Steve Roughton

Oracle Label Security(Oracle標籤安全性)按行來控制使用者的訪問。

絕大多數商業應用程式都必須處理安全性問題。應用程式經常需要限制對專用記錄的訪問、建立審計跟蹤,或者執行一個工作流過程,所有這些都要符合公司的安全策略。構建安全的軟體是一個富有挑戰性且複雜的工作,在整個機構內管理軟體的安全策略可能會更困難。

作為模式(schema)設計人員,你可能會在表中新增安全性列並根據這些表建立使用者特定的檢視。作為DBA,你可能會建立角色和許可權來保護資料庫物件。而作為開發人員,你可能會編寫PL/SQL包,將安全事務處理封裝在應用程式內。所有這些技術都很有效,但這些方法也都具有一定的缺點。例如,某人可能會無意中將專用資料匯出至一個個人模式、原有的應用程式可能與安全物件不相容,或者使用者可能會利用SQL*Plus繞過整個應用程式的安全性檢查。

Oracle9i資料庫有一個可以幫助解決這些問題的元件:Oracle Label Security。Oracle Label Security最早引入Oracle8i第三版(8.1.7),它是一個使你能夠建立並實施企業安全性策略的簡捷工具。

Oracle Label Security是內建於資料庫引擎中的過程與約束條件集,該資料引擎實施對在單個表或整個模式上的”行”級訪問控制。要利用Oracle Label Security,需要建立一個或多個安全策略,其中每一個安全策略都包含一組標籤。你可以用這些標籤來標明哪些使用者能夠訪問什麼型別資料。在建立了一個策略之後,將該策略應用於需要保護的表,並將這些標籤授予你的使用者,這樣,你就完成了整個過程。Oracle Label Security對查詢的修改是透明的,並且在即時計算訪問級別,以執行你的新策略。

當Oracle9i資料庫在解析各個SQL語句時,它也檢測各個表是否受到某個安全策略的保護。根據該使用者的訪問許可權,Oracle9i資料庫向該語句的WHERE子句中新增安全性謂詞。因為這些都發生在資料庫引擎的內部,所以不管該SQL語句的來源如何,使用者都不可能繞過該安全性機制。

它是如何工作的?

這裡有一個非常簡單的例子,可以說明Oracle Label Security是如何工作的。我們建立了名為documents的表,並向其中填入了4個記錄,同時定義了兩個安全級別:PUBLLIC(公共)與INTERNAL(內部)。每個級別各有一個數字值:1000或2000。接著可以為表的每一行指定一個級別。下面給出對該表進行的一個簡單SELECT:

 

SQL> SELECT * FROM documents;

DOCID DOCNAME LEVEL DOC_LABEL
—– ———– ——– ———
1 SHARE_WARE PUBLIC 1000
2 WEST_PAYROLL INTERNAL 2000
3 EAST_SALES INTERNAL 2000
4 COMP_PAYROLL INTERNAL 2000

 

現在假定在我們的資料庫中有兩個使用者:EMP與MGR。我們為這些使用者指定如下訪問級別:

EMP 被指定為 PUBLIC只讀。

MGR 被指定為 PUBLIC與INTERNAL 讀/寫。
當這兩個使用者訪問該表時,EMP只能讀取第1行,而MGR可以對所有4行進行讀/寫操作。
 

當這兩個使用者訪問此 documents表時,其內部會發生什麼呢?假定EMP使用者執行下面的查詢:

 

SELECT * FROM documents;

 

Oracle9i資料庫對該查詢進行解析,並判定該表是受標籤安全性的保護。Oracle Label Security向該查詢中新增一個 WHERE 子句,以確保該EMP只能看到標記有 PUBLIC 訪問的行:

 

SELECT * FROM documents
WHERE doc_label = 1000;

 

下面是該 EMP 使用者在執行此查詢後所看到的內容:

 

DOCID DOCNAME LEVEL DOC_LABEL
—– ———- —— ———
1 SHARE_WARE PUBLIC 1000

你可能想知道:”為什麼不根據某一列值,建立一個限制訪問的檢視呢?”事實上,如果你的應用程式只需要幾個級別,並沒有特殊的安全要求要考慮,那麼向你的表中新增一個安全性列,然後再利用檢視就可以了。

但假設你的系統要求發生了變化,你現在需要利用對改變資料集的定製的讀/寫許可跨多個機構來管理數個級別的使用者。此外,這些機構位於不同的國家,各自都有自己的法律和安全性限制。如果僅使用檢視,就很難滿足這些要求了。

幸運的是,Oracle Label Security就是為了適應擴充套件而設計的,因此實施此類應用程式安全性可能比你預計的更容易。

一個練習示例

實施Oracle Label Security包括以下10個步驟:

安裝Oracle Label Security(每個資料庫進行一次)
建立安全性策略
定義級別
定義區間(compartment)(可選)
定義分組(可選)
建立標籤
將標籤策略應用於表
指定使用者標籤
指定正常授權級別的訪問
為表中的行指定合適的標籤
在使用Oracle Label Security時,可以利用Oracle Enterprise Manager的Policy Manager圖形使用者介面(GUI)或者Oracle Label Security PL/SQL包。在我們的示例實施中,我們將利用PL/SQL包。相同的概念可以應用於上述兩種技術中的任一種。

 

步驟1;安裝Oracle Label Security
對於每一個資料庫只需要安裝一次Oracle Label Security。安裝過程包括4個步驟:

啟動Universal Installer。
選擇並安裝該Oracle Label Security選項。
以SYS身份按下面的方式執行$ORACLE_HOME/rdbms/ admin/catols.sql:
 

 

SQL> CONN sys/password AS SYSDBA;
SQL> @?/rdbms/admin/catols

 

注意:此catols.sql指令碼在其最後一步對資料庫進行SHUTDOWN IMMEDIATE (立即關閉)。

重新啟動例項並執行
 

 

SQL> SELECT username FROM dba_users;

 

你將看到一個新的包括所有Oracle Label Security物件的 LBACSYS使用者。其預設口令是LBACSYS (所以一定要更改該口令)。該使用者將管理你的安全策略。

步驟2:建立一個安全性策略
下一個任務是建立一個安全性策略。一個策略就是一個包括所有安全規則和訪問要求的儲存桶(bucket)。行級別的資料標籤和對這些行的模式訪問總是與一個策略相關聯。

在本例中,你需要定義對公司文件的行級別的訪問。在此步驟內,建立一個名為DOC_POLICY的策略。要建立一個策略,先以LBACSYS身份建立連線,然後利用 sa_sysdb.create_policy過程:

 

SQL> CONN lbacsys/lbacsys
SQL> EXEC sa_sysdba.create_policy
(`DOC_POLICY`,`DOC_LABEL`);

 

第一個引數DOC_POLICY是該策略的名字,第二個引數DOC_LABEL是一個列的名字,Oracle Label Security將把該列新增到你將在標籤控制下替換的表內。

為了核實你的策略已經建立,可按下面方式查詢DBA_SA_POLICIES :

 

SQL> SELECT policy_name, status
from DBA_SA_POLICIES;

POLICY_NAME STATUS
———– ——-
DOC_POLICY ENABLED

 

要禁用、重新啟用或者刪除一個策略,可利用以下過程:

 

SQL> EXEC sa_sysdba.disable_policy
(`DOC_POLICY`);
SQL> EXEC sa_sysdba.enable_policy
(`DOC_POLICY`);
SQL> EXEC sa_sysdba.drop_policy
(`DOC_POLICY`);

 

步驟3:定義級別
每個安全性策略都必須包含指定訪問表的不同等級的級別。在本例中,建立了兩個敏感度級別: PUBLIC與 INTERNAL。

 

SQL> EXEC sa_components.create_level
(`DOC_POLICY`, 1000,
`PUBLIC`, `Public Level`);
SQL> EXEC sa_components.create_level
(`DOC_POLICY`, 2000,
`INTERNAL`, `Internal Level`);

 

每個級別都有一個策略名、一個數字ID、一個縮寫名與一個全名。該數字ID表示敏感度級別–編號越高,表明敏感度越高。在本例中,INTERNAL 比PUBLIC的敏感度要高。為了檢視你所建立的級別,執行下面過程:

 

SQL> SELECT * FROM dba_sa_levels
ORDER BY level_num;

 

步驟4:定義區間(可選)
區間使你能夠將對一行資料的訪問精確限定在一個級別之內。在本例中,你具有閱讀敏感度級別相同的文件,但是某一區間只能看到該級別的子集。下面你要建立FINANCE 與 HUMAN_RESOURCE區間:

 

SQL> EXEC sa_components.create_compartment
(`DOC_POLICY`, 200,
`FIN`, `FINANCE`);
SQL> EXEC sa_components.create_compartment
&nb

sp; (`DOC_POLICY`, 100,
`HR`, `HUMAN_RESOURCE`);

 

區間有一個策略名、一個數字ID、一個縮寫名與一個全名。區間的數字ID並不指定其敏感度的級別。它僅用於在顯示訪問資訊時對區間進行排序。要了解關於區間的資訊,可以查詢DBA_SA_COMPARTMENTS檢視。

步驟5:定義分組(可選)
和使用區間類似,使用分組是將訪問限制在一個級別內的另一個可選用的方法。當有多個層次的使用者時(如在一個公司的機構設定圖中),組是非常有用的。

在建立一個分組時,必須定義一個層次(hierarchy)。在本例中,ALL_REGIONS是父,WEST_REGION和EAST_REGION是ALL_REGIONS的子。

 

SQL> EXEC sa_components.create_group
(`DOC_POLICY`, 10,
`ALL`, `ALL_REGIONS`);
SQL> EXEC sa_components.create_group
(`DOC_POLICY`, 20, `WEST`,
`WEST_REGION`, `ALL`);
SQL> EXEC sa_components.create_group
(`DOC_POLICY`, 30, `EAST`,
`EAST_REGION`, `ALL`);

 

與區間類似,分組也具有一個數字ID、一個縮寫名和一個全名。此外編號(數字)並不表示任何敏感度,它僅用於在顯示分組資訊時對其進行排序。要觀察關於分組的資訊,可查詢DBA_SA_GROUPS檢視。

步驟6:建立標籤
一個標籤是級別、區間和分組的一個組合。每個標籤都必須包含一個級別,還可以包含(也可以不包含)區間和/或分組。該標籤使你能夠將資料的不同使用者所要求的各種不同型別訪問迅速地組合在一起。

標籤是級別、區間與分組的縮寫名的一個組合,並遵循以下語法:

 

級別: 區間, … 區間_n:分組,.. 分組_n
 

級別、區間與分組都必須用冒號隔開。如果指定了一個以上的區間或組,它們必須用逗號隔開。

例如,可能有一些財務部門的使用者,他們只能訪問內部文件。其標籤類似於:

 

INTERNAL:FIN(內部:財務)
建立4個標籤來指定相關要求,如下面所示:
SQL> EXEC sa_label_admin.create_label
(`DOC_POLICY`, `10000`,
`PUBLIC`, TRUE);
SQL> EXEC sa_label_admin.create_label
(`DOC_POLICY`, `20200`,
`INTERNAL:HR:WEST`, TRUE);
SQL> EXEC sa_label_admin.create_label
(`DOC_POLICY`, `20400`,
`INTERNAL:FIN:EAST`, TRUE);
SQL> EXEC sa_label_admin.create_label
(`DOC_POLICY`, `30900`,
`INTERNAL:HR,FIN:ALL`, TRUE);

在建立一個標籤時,必須為其指定一個編號。該編號在資料庫的所有策略中是惟一的。要檢視標籤資訊,可查詢DBA_SA_LABELS檢視。

步驟7:將標籤策略應用於表
要將一個表置於標籤安全性控制之下,需要把該標籤策略賦給該表。在下面的過程中,將DOC_POLICY應用於使用者APP所擁有的DOCUMENTS表。Oracle Label Security將控制對該表的讀/寫訪問。

 

SQL> EXEC sa_policy_admin.apply_table_policy –
( policy_name => `DOC_POLICY` –
, schema_name => `APP` –
, table_name => `DOCUMENTS` –
, table_options => `LABEL_DEFAULT,
READ_CONTROL,WRITE_CONTROL`);

在執行此過程時,Oracle9i資料庫向documents表中新增一個名為DOC_LABEL的列。這個列的名字是在步驟2中建立該安全策略時定義的。如果你描述該documents表,你將看到如下所示的新的DOC_LABEL列:

 

SQL> DESC app.documents

Name Type
——— ————
DOCID NUMBER
DOCNAME VARCHAR2(30)
DOC_LABEL NUMBER(10)

 

當你應用該策略時,你也可以通過在TABLE_OPTIONS引數中指定HIDE,取消來自使用者的該列:

 

table_options&n

            bsp; => `LABEL_DEFAULT,
READ_CONTROL,WRITE_CONTROL,HIDE`            

 

這個TABLE_OPTIONS引數使你能夠定義將把什麼型別的控制應用到該表上。LABEL_DEFAULT指明,如果沒有為一個 INSERT語句提供標籤,那麼將使用預設的會話行標籤。READ_CONTROL引數規定該 SELECT, UPDATE和DELETE訪問在整個標籤內是有效的。WRITE_CONTROL引數決定哪些INSERT, UPDATE活動是通過一個標籤獲得授權的。

要確定哪些策略已經被應用到了哪些表和模式,可以查詢DBA_SA_TABLE_POLICIES檢視。

步驟8:指定使用者標籤
現在需要定義在一個策略中哪些使用者具有什麼型別的訪問許可權。這也是你給一個使用者指定最大讀/寫許可權的地方。在本例中,你為3個使用者指定標籤如下:

MGR被賦予了最高階別的讀/寫許可權。
HR_EMP被賦予了對 HR WEST 文件的某個讀/寫訪問許可權。
EMP被賦予了PUBLIC 讀/寫訪問許可權。
程式碼清單1給出了用於為各個使用者指定標籤的語法。
 

這些過程將一個使用者對映到訪問級別和被指定了標籤的行。為了檢視使用者及訪問級別,可查詢DBA_SA_USER_LABELS檢視。

步驟9:指定正常授權級別的訪問
要確保CRUD(CREATE, READ, UPDATE, 和 DELETE)訪問已經準備就序。Label Security是與正規的表授權一起工作的。在完成CRUD授權之前,使用者不能進行SELECT, INSERT, UPDATE, 或 DELETE 或DELETE操作。當一個SQL查詢訪問一個表時,Oracle Label Security將首先檢查CRUD訪問是否合適,然後,如果有一個安全策略被應用於一個表,則它將確保該訪問被執行。下面所列的是對使用者進行合適的CRUD授權的過程:

 

SQL> CONN app/app
SQL> GRANT SELECT ON documents TO emp;
SQL> GRANT SELECT, UPDATE ON documents
TO hr_emp;
SQL> GRANT SELECT, UPDATE, INSERT
ON documents TO mgr;

 

步驟10:指定合適的標籤
現在,確保為每個行都指定一個合適的標籤。在本例中,將從頭開始載入資料。既可以用其數字形式載入該標籤,也可以用CHAR_TO_LABEL函式來載入。本例對這兩種方法都進行了說明。以MGR身份建立連線,將該資料插入到APP.DOCUMENTS表中:

 

SQL> CONN mgr/mr_bigg
SQL> INSERT INTO app.documents VALUES
(1, `SHARE_WARE`,CHAR_TO_LABEL
(`DOC_POLICY`,`PUBLIC`));
SQL> INSERT INTO app.documents VALUES
(2, `WEST_PAYROLL`, 20200);
SQL> INSERT INTO app.documents VALUES
(3, `EAST_SALES`, 20400);
SQL> INSERT INTO app.documents VALUES
(4, `COMP_PAYROLL`, 30900);

 

如果表中已經有了資料,那麼你需要用合適的標籤值來更新該標籤列(DOC_LABEL)。因為該表已經處於Oracle Label Security 控制之下,所以必須用一個具有許可權的模式來更新該標籤列。當然,也可以暫時禁用該策略,先更新該標籤列,然後再重新啟用該策略。如果用SQL*Loader向一個受保護的表中插入資料,則先要確保載入的使用者(模式)具有合適的標籤寫入許可權。

對一個表啟用了標籤安全性控制後,如果沒有合適的標籤許可權,即便是表的所有者也不能讀取或寫入。該規則的一個變體是,表的所有者可以在沒有Oracle Label Security DELETE許可的條件下截短其資料。

運算元據

現在當你以不同的使用者身份連線時,請注意你只能按照你的安全性策略和CRUD訪問所規定的那樣運算元據:

 

SQL> CONN mgr/mr_bigg
SQL> SELECT docname, doc_label
FROM app.documents;
DOCNAME DOC_LABEL
————- ———
SHARE_WARE 10000
WEST_PAYROLL 20200
EAST_SALES 20400
COMP_PAYROLL 30900

 

如果以HR_EMP身份連線,則相同的查詢將返回以下內容:

 

DOCNAME DOC_LABEL
————- ———
SHARE_WARE 10000
WEST_PAYROLL 20200

 

如果以 EMP身份連線,相同的查詢則只返回以下內容:

 

DOCNAME

            DOC_LABEL
————- ———
SHARE_WARE 10000            

 

當任一SQL語句訪問該APP.DOCUMENTS表時,Oracle9i資料庫首先驗證CRUD訪問,然後施以Oracle Label Security限制。這樣,使用者只能執行經授權的操作。

DBA應考慮的事項

如果你是一位DBA,那麼還有另外一些需要考慮的事項。當你匯出受Label Security保護的資料時,只能使用一個具有所賦予的適當讀取許可權的模式匯出該資料。例如,如果你想以SYSTEM身份匯出APP.DOCUMENTS 表,將會得到以下訊息:

 

EXP-00079: Data in table “DOCUMENTS” is protected.(表”DOCUMENTS”中的資料受到保護)

Conventional path may only be exporting partial table.(常規的路徑只能匯出部分表)

. . exporting table DOCUMENTS 0 rows exported(匯出表DOCUMENTS中的0行被匯出)
 

你不能將一個安全性策略應用於該SYSTEM 模式。你將需要利用一個對錶中受標籤保護的所有行有讀取許可權的非SYSTEM模式。例如,如果你有一個用來匯出你的資料庫的EXPUSER 模式,則你需要授予它對受策略保護的所有行的特殊READ許可權:

 

SQL> EXEC sa_user_admin.set_user_privs
(`DOC_POLICY`,`EXPUSER`,`READ`);

要授予一個模式對受策略保護的資料的完全讀取和寫入許可權,則可以利用FULL關鍵詞:

 

SQL> EXEC sa_user_admin.set_user_privs
(`DOC_POLICY`,`EXPUSER`,`FULL`);

注意:任何被授予SYSDBA許可權的模式(如SYS)都可以看到所有資料,而不管這些資料是否受Label Security保護。

無論你有什麼特殊許可權(如FULL,全權),你都不能利用匯出實用程式來備份LBACSYS模式。如果你試圖匯出LBACSYS,你將收到一個出錯提示:”LBACSYS is not a valid username.(LBACSYS不是一個有效使用者名稱)”。因此,你需要利用資料庫的一個物理備份(熱備份、冷備份或RMAN)來備份LBACSYS的物件。

在將受標籤保護的資料匯入另一個資料庫之前,需要先安裝Oracle Label Security。還需要預先建立策略和標籤,並確保匯入的模式(使用者)具有完全的寫入許可權。具體細節,請參見Oracle Label Security管理員指南第12章。

如果有大量受Label Security保護的資料,那麼你就需要一個調優策略。根據標籤基數(cardinality)的不同,你可能希望考慮向標籤列中增加一個B樹索引或一個位對映索引。例如,如果標籤的基數較高,那麼就應當使用一個B樹索引。

Oracle建議對LBACSYS模式的物件以及應用程式表和索引進行分析,以改進由基於成本的優化器所生成的執行計劃。我們建議在對安全性策略進行任何改變後,對LBACSYS物件進行分析。

結論

Oracle9i資料庫中的Oracle Label Security提供了一種對資料進行細粒度訪問控制的安全的方法。這一特性被封裝在資料庫引擎中,所以不可能繞過它,它提供了一種實施和維護複雜”行”級別安全性所需要的安全的方法。


相關文章