作者: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提供了一種對資料進行細粒度存取控制的安全的方法。這一特性被封裝在資料庫引擎中,所以不可能繞過它,它提供了一種實施和維護複雜"行"層級安全性所需要的安全的方法。 |