現(xiàn)實問題的細粒度審計,第 3 部分
作者:Arup Nanda
現(xiàn)在您已經(jīng)掌握了各種環(huán)境中的 FGA,下面您將了解到它如何能夠在 Oracle Database 10g 中起到更大的作用
在本系列的前兩個部分中,我向您介紹了細粒度審計 (FGA) 的概念,它用來在 Oracle9i Database 和更高版本中跟蹤選定的語句。我還說明了如何在復(fù)雜的環(huán)境中(比如說在一個 Web 應(yīng)用程序內(nèi)部)通過應(yīng)用程序上下文和客戶端標(biāo)識符來使用這個特性。這兩篇文章為您提供了足夠的信息,使您可以為幾乎所有類型的數(shù)據(jù)庫系統(tǒng)(無論它有多復(fù)雜)構(gòu)建一個 FGA 設(shè)置程序。在這個第三部分,同時也是最后一部分中,我將說明 Oracle Database 10g 為表帶來的 FGA 增強。
Oracle9i Database 中的 FGA
讓我們簡要地重述一下 FGA 的好處。關(guān)于完整的討論,請參考本系列的第 1 部分和第 2 部分。
正規(guī)審計(通過 AUDIT 語句)記錄使用的語句 — 如 SELECT 或 INSERT — 以及誰發(fā)出它、從哪一個終端、什么時候等等。然而,信息最重要的部分 — 哪條特定記錄被修改了,以及數(shù)據(jù)本身的變化 — 沒有捕獲到。相反,許多用戶編寫觸發(fā)器來捕獲變化前后的數(shù)據(jù)值,并把它們記錄在用戶自定義的表中。但因為觸發(fā)器只可能在 DML 語句(如 insert、update 和 delete)上使用,所以訪問的一個主要的方面 — SELECT 語句 — 不能通過這種途徑來審計。
因此 FGA 的價值在于:它只捕獲 SELECT 語句。與觸發(fā)器和 Log Miner 工具一起,F(xiàn)GA 提供了一種機制來審計各種類型的值修改和不涉及到修改的數(shù)據(jù)訪問。
FGA 不僅填補了審計 SELECT 語句的空白,而且還提供了其它的一些引人注目的額外好處,這些好處使得數(shù)據(jù)庫管理員的工作變得更加輕松。例如,F(xiàn)GA 允許一個用戶自定義的過程在指定的審計條件出現(xiàn)的時候執(zhí)行,因此您可以認為它是 SELECT 語句上的一個觸發(fā)器 — 這是一個在其它方式下沒有提供的功能。這個技巧可能非常有用 — 例如,任何時候當(dāng)有人選擇了收入超過 1 百萬美元的員工的工資記錄時,發(fā)送一封郵件給一個安全審計員,以在用戶自定義的表中生成審計記錄,這些表可以不受限制地進行處理(這與 SYS 擁有的 FGA_LOG$ 表不同);利用審計線索識別數(shù)據(jù)訪問類型,以找出最可能的索引機制等等。
由于這些及其它的原因,F(xiàn)GA 成為數(shù)據(jù)庫管理員工具箱中最重要的工具之一。不過,在 Oracle9i Database 中,它缺少一個重要的特性:在 SELECT 語句之外的語句上使用。
所有類型的 DML
在 Oracle Database 10g 中,F(xiàn)GA 已變得很完善 — 它可以審計所有類型的 DML 語句,而不只是 SELECT。
讓我們看一個例子。在本系列的第 1 部分中,我介紹了一個名稱為 ACCOUNTS 的表。在那個表上定義的 FGA 策略為:
begindbms_fga.add_policy (object_schema => 'BANK',object_name => 'ACCOUNTS',policy_name => 'ACCOUNTS_ACCESS',audit_column => 'BALANCE',audit_condition => 'BALANCE >= 11000');end;
在 Oracle 9i Database 下,這個策略只能審計 SELECT 語句。然而,在 Oracle Database 10g 中,您可以擴展它,使它包含 INSERT、UPDATE 和 DELETE。您可以通過指定一個新的參數(shù)來實現(xiàn)這個目的:
statement_types => 'INSERT, UPDATE, DELETE, SELECT'
這個參數(shù)將在所有包括的語句類型上啟用審計。您甚至可能考慮為每種語句類型創(chuàng)建單獨的策略,這將允許您隨意地啟用和禁用策略 — 尤其是,控制審計線索的創(chuàng)建,以管理它們占用的空間。不過,statement_type 參數(shù)默認情況下只審計 SELECT 語句。
在策略中添加新的參數(shù)之后,發(fā)出以下語句:
update accounts set balance = 1200 where balance >= 3000;
這將使一條記錄插入到 FGA_LOG$ 表中。注意這條記錄是由一個自動事務(wù)插入的;即使您回滾 update 語句,這條記錄也將存在。您可以從另一個會話來檢查線索是否存在。
select lsqltext from fga_log$;LSQLTEXT--------------------------------------------------------update accounts set balance = 3100 where balance >= 3000
該行還包括其它所有的相關(guān)詳細信息(如表名稱、策略名稱和事務(wù) ID)。
與觸發(fā)器方法相比較
那么 FGA 能做什么原來的基于觸發(fā)器的方法不能做的事情?
在 Oracle Database 10g 之前,DML 語句審計是在一個觸發(fā)器中進行的,類似于以下方式(注意:這不是真實的代碼,只是一個代表性的示例):
CREATE TRIGGER XXXXXON TableAFTER INSERT OR UPDATE OR DELETEFOR EACH ROWBEGININSERT INTO AUDIT_LOGOld Value, New Value, Time .....END
觸發(fā)器捕獲舊的值和新的值,并填充 AUDIT_LOG 表。如果需要,還可以將它變?yōu)樽詣邮聞?wù)。最大的問題是觸發(fā)器是對每行觸發(fā)的,而不是每條語句一次。例如,以下語句:
update accounts set balance = 1200 where balance >= 3000;
對全部 10,000 條記錄觸發(fā),在審計表中插入 10,000 行。這種方法可能嚴(yán)重地損害 update 語句的性能,甚至可能因?qū)徲嬀€索中的空間問題而導(dǎo)致失敗。使用語句觸發(fā)器也無濟于事,因為它不能捕獲個別記錄的任何新的或舊的值。比較而言,在 FGA 方法中,只創(chuàng)建一條記錄,并且插入只在每條語句上執(zhí)行一次,而不是每行一次 — 即使有的話,對性能的影響也很小。
在 FGA 中,您可以指定相關(guān)的列來限定審計線索僅在這些列被訪問時才創(chuàng)建。在觸發(fā)器中,通過使用觸發(fā)器定義的 WHERE,這種功能也可以實現(xiàn)。不過,其中存在一個非常重要的差異 — 在觸發(fā)器中,只有當(dāng)列被修改時(而不是被訪問時)才檢查它們。在 FGA 中,無論何時列被訪問(無論它們被修改與否),審計就開始。這個特性使得 FGA 比觸發(fā)器具有更多的功能。
另一個優(yōu)點是 FGA 工具的適用性。有時,在一個視圖上定義的 INSTEAD OF 觸發(fā)器在基表上更新視圖;另一個 INSTEAD OF 觸發(fā)器不能捕獲由其它的觸發(fā)器所作的修改,因此這些修改不能被記錄。然而,F(xiàn)GA 是建立在視圖或表的基礎(chǔ)上的,它能夠捕獲變化,而不論變化來自哪里 — 用戶語句或觸發(fā)器。
那么,是否存在觸發(fā)器比 FGA 更好的情況呢?可能有兩種情況:
在變化期間 FGA 的行為
數(shù)據(jù)始終在變化,因此它有可能變得適用于審計條件 — 雖然之前它不適用于審計條件,反之亦然。這個問題帶來了一些關(guān)于 FGA 在不同情況下的行為的有趣問題??紤]我們的例子,其中在 UPDATE 上已經(jīng)定義了 FGA 策略,條件為 BALANCE >= 3000,審計列是 BALANCE。
第 1 種情況
之前:BALANCE = 1000
用戶發(fā)出:
update accounts set balance = 1200 where ACCOUNT_NO = ....
舊的和新的 balance 都小于 3,000,審計條件不滿足;因此這條語句將不會被審計。
第 2 種情況
之前:BALANCE = 1000
用戶發(fā)出:
update accounts set balance = 3200 where ACCOUNT_NO = ....
新的 balance 大于 3,000,審計條件滿足;因此這條語句將 會被審計。
第 3 種情況
之前:BALANCE = 3200
用戶發(fā)出:
update accounts set balance = 1200 where ACCOUNT_NO = ....
新的 balance 小于 3,000,但舊的 balance 大于 3,000。因此審計條件滿足,這條語句將被審計。
第 4 種情況
用戶插入一行,其中有 BALANCE < 3000。
insert into accounts values (9999,1200,'X');
因為 balance 1,200 不滿足審計條件,所以這條語句不被審計。如果 balance 列大于或等于 3,000,它將被審計。
第 5 種情況
用戶插入一行,其中 balance 的值為空。
insert into accounts (account_no, status) values (9997, 'X');
因為 balance 為空,該列沒有任何默認值,所以審計條件不滿足(比較 NULL >= 3000 結(jié)果為 FALSE),這條語句不會被審計。重要注意事項:假設(shè)該列有一個大于 3,000 的默認值時,這條語句仍然不會被審計,即使插入行的 balance 列值大于 3000。
所有相關(guān)的列?
考慮在表 ACCOUNTS 上定義的一個策略,如下:
begindbms_fga.add_policy (object_schema => 'ANANDA',object_name => 'ACCOUNTS',policy_name => 'ACCOUNTS_SEL',audit_column => 'ACCOUNT_NO, BALANCE',audit_condition => 'BALANCE >= 3000',statement_types => 'SELECT');end;
您可以看到,策略是在 ACCOUNT_NO 和 BALANCE 上定義的。假定帳戶 9995 的余額是 3,200,如果用戶發(fā)出以下語句:
select balance from accounts where account_no = 9995;
這條語句將被審計,因為 balance 列被選中,且余額為 3,200,大于 3,000,滿足審計條件。不管這三個列中哪一個被選中,都將觸發(fā)審計。
在某些情況下,列的組合可能很重要,而不是某個特定的列。例如,如果一個用戶想查出在銀行的總余額,她發(fā)出:
select sum(balance) from accounts;
這條查詢幾乎沒什么害處;它不明確指出帳戶所有者和帳戶余額。Acme Bank 安全策略可能不會要求審計這條查詢。不過,這條查詢
select balance from accounts where account_no = 9995
必須被審計;因為它明確地指定了一個帳戶。默認地,所有語句都被審計(無論使用了什么樣的列組合)。這將創(chuàng)建大量不需要的審計線索項目,并可能帶來一些空間限制問題。為了限制它們,您可以指定僅當(dāng)在查詢中使用了希望的列組合時才開始審計。當(dāng)定義策略時,您可以使用一個新的參數(shù):
audit_column_opts => DBMS_FGA.ALL_COLUMNS
這個參數(shù)將使策略僅當(dāng)列 ACCOUNT_NO 和 BALANCE 在查詢中都被訪問時才創(chuàng)建審計線索項目。例如,以下查詢將產(chǎn)生一個審計線索項目。
select account_no, balance from accounts;
但這條查詢不會產(chǎn)生審計線索項目。
select account_no from accounts;
使用這個參數(shù)將把審計的數(shù)量限制在一個更易管理的大小。如果希望采用默認的行為 — 即任意列被選中時都進行審計,那么您可以對同一參數(shù)的使用不同值。
audit_column_opts => DBMS_FGA.ANY_COLUMNS
捕獲賦值變量
利用 Oracle Database 10g,其它的有用信息(如在查詢中使用的賦值變量的值)可以寫到常規(guī)的審計線索中。您可以通過設(shè)置初始化參數(shù)來執(zhí)行這項任務(wù)
audit_trail = DB_EXTENDED
在 FGA 審計線索中,獲取賦值變量的值可能有意義也可能沒意義。如果您想要停止記錄這些值,您可以在 add_policy() 過程中使用另一個參數(shù),如下:
audit_trail => DB
默認情況下,捕獲賦值變量,這個參數(shù)的值為 DB_EXTENDED。
全部綜合在一起
現(xiàn)在您已經(jīng)了解了 Oracle Database 10g 中的幾個新的 FGA 參數(shù),下面讓我們看看策略創(chuàng)建腳本的聲明現(xiàn)在是什么樣子。
下面我們定義對應(yīng)四種語句類型的四種不同的策略。SELECT 語句的策略顯示如下,這里我們選擇了不記錄賦值變量的值,并僅當(dāng)列 ACCOUNT_NO 和 BALANCE 在查詢中都被使用時才觸發(fā)審計。
begindbms_fga.add_policy (object_schema => 'ANANDA',object_name => 'ACCOUNTS',policy_name => 'ACCOUNTS_SEL',audit_column => 'ACCOUNT_NO, BALANCE',audit_condition => 'BALANCE >= 3000',statement_types => 'SELECT',audit_column_opts => DBMS_FGA.ALL_COLUMNS,audit_trail => DB);end;
同樣,我們將為 INSERT、UPDATE 和 DELETE 語句創(chuàng)建類似的策略。它們可以隨意地啟用或禁用。
結(jié)合常規(guī)審計和細粒度審計
在 Oracle Database 10g 中,常規(guī)審計也得到了巨大的改進。通過 AUDIT 命令執(zhí)行常規(guī)審計,它現(xiàn)在能夠捕獲大量其它有用的信息,例如:
您可以看到,在內(nèi)容和功能方面,常規(guī)審計類似于細粒度審計。然而,作為一個數(shù)據(jù)庫管理員,您有興趣知道所有的審計項目,而不只是一個審計項目。一個新的視圖,DBA_COMMON_AUDIT_TRAIL,結(jié)合了常規(guī)線索和 FGA 線索。用以下查詢來檢查它們二者:
select * from dba_common_audit_trail;
這個視圖結(jié)合了 DBA_AUDIT_TRAIL 和 DBA_FGA_AUDIT_TRAIL,擁有來自每個視圖的相關(guān)信息。這個視圖從數(shù)據(jù)字典中創(chuàng)建,如下所示。
select 'Standard Audit', SESSIONID,PROXY_SESSIONID, STATEMENTID, ENTRYID, EXTENDED_TIMESTAMP, GLOBAL_UID,USERNAME, CLIENT_ID, Null, OS_USERNAME, USERHOST, OS_PROCESS, TERMINAL,INSTANCE_NUMBER, OWNER, OBJ_NAME, Null, NEW_OWNER,NEW_NAME, ACTION, ACTION_NAME, AUDIT_OPTION, TRANSACTIONID, RETURNCODE,SCN, COMMENT_TEXT, SQL_BIND, SQL_TEXT,OBJ_PRIVILEGE, SYS_PRIVILEGE, ADMIN_OPTION, GRANTEE, PRIV_USED,SES_ACTIONS, LOGOFF_TIME, LOGOFF_LREAD, LOGOFF_PREAD, LOGOFF_LWRITE,LOGOFF_DLOCK, SESSION_CPUfrom DBA_AUDIT_TRAILUNION ALLselect 'Fine Grained Audit', SESSION_ID,PROXY_SESSIONID, STATEMENTID, ENTRYID, EXTENDED_TIMESTAMP, GLOBAL_UID,DB_USER, CLIENT_ID, EXT_NAME, OS_USER, USERHOST, OS_PROCESS, Null,INSTANCE_NUMBER, OBJECT_SCHEMA, OBJECT_NAME, POLICY_NAME, Null,Null, Null, STATEMENT_TYPE, Null, TRANSACTIONID, Null,SCN, COMMENT$TEXT, SQL_BIND, SQL_TEXT,Null, Null, Null, Null, Null,Null, Null, Null, Null, Null,Null, Nullfrom DBA_FGA_AUDIT_TRAIL
FGA 和常規(guī)審計:差異
如果標(biāo)準(zhǔn)審計和細粒度審計在 Oracle Database 10g 中是類似的,您可能要問,在什么情況下,F(xiàn)GA 將是更好的選擇?好的,讓我們研究一下它們的差異。
通過上面的比較,您將了解為什么可以證明 FGA 在某些情況下很有用。利用 Oracle Database 10g 中的增強的常規(guī)審計特性,一些以前認為不可能的任務(wù) — 例如捕獲賦值變量的值 — 變得十分容易。