oracle審計-細粒度(轉)

zhouwf0726發表於2019-07-08
安全性和身份管理

現實問題的細粒度審計,第 3 部分
作者:Arup Nanda

現在您已經掌握了各種環境中的 FGA,下面您將瞭解到它如何能夠在 Oracle Database 10g 中起到更大的作用

在本系列的前兩個部分中,我向您介紹了細粒度審計 (FGA) 的概念,它用來在 Oracle9i Database 和更高版本中跟蹤選定的語句。我還說明了如何在複雜的環境中(比如說在一個 Web 應用程式內部)通過應用程式上下文和客戶端識別符號來使用這個特性。這兩篇文章為您提供了足夠的資訊,使您可以為幾乎所有型別的資料庫系統(無論它有多複雜)構建一個 FGA 設定程式。在這個第三部分,同時也是最後一部分中,我將說明 Oracle Database 10g 為錶帶來的 FGA 增強。

Oracle9i Database 中的 FGA

讓我們簡要地重述一下 FGA 的好處。關於完整的討論,請參考本系列的第 1 部分第 2 部分

正規審計(通過 AUDIT 語句)記錄使用的語句 — 如 SELECT 或 INSERT — 以及誰發出它、從哪一個終端、什麼時候等等。然而,資訊最重要的部分 — 哪條特定記錄被修改了,以及資料本身的變化 — 沒有捕獲到。相反,許多使用者編寫觸發器來捕獲變化前後的資料值,並把它們記錄在使用者自定義的表中。但因為觸發器只可能在 DML 語句(如 insert、update 和 delete)上使用,所以訪問的一個主要的方面 — SELECT 語句 — 不能通過這種途徑來審計。

因此 FGA 的價值在於:它只捕獲 SELECT 語句。與觸發器和 Log Miner 工具一起,FGA 提供了一種機制來審計各種型別的值修改和不涉及到修改的資料訪問。

FGA 不僅填補了審計 SELECT 語句的空白,而且還提供了其它的一些引人注目的額外好處,這些好處使得資料庫管理員的工作變得更加輕鬆。例如,FGA 允許一個使用者自定義的過程在指定的審計條件出現的時候執行,因此您可以認為它是 SELECT 語句上的一個觸發器 — 這是一個在其它方式下沒有提供的功能。這個技巧可能非常有用 — 例如,任何時候當有人選擇了收入超過 1 百萬美元的員工的工資記錄時,傳送一封郵件給一個安全審計員,以在使用者自定義的表中生成審計記錄,這些表可以不受限制地進行處理(這與 SYS 擁有的 FGA_LOG$ 表不同);利用審計線索識別資料訪問型別,以找出最可能的索引機制等等。

由於這些及其它的原因,FGA 成為資料庫管理員工具箱中最重要的工具之一。不過,在 Oracle9i Database 中,它缺少一個重要的特性:在 SELECT 語句之外的語句上使用。

所有型別的 DML

在 Oracle Database 10g 中,FGA 已變得很完善 — 它可以審計所有型別的 DML 語句,而不只是 SELECT。

讓我們看一個例子。在本系列的第 1 部分中,我介紹了一個名稱為 ACCOUNTS 的表。在那個表上定義的 FGA 策略為:

begin
   dbms_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。您可以通過指定一個新的引數來實現這個目的:

statement_types => 'INSERT, UPDATE, DELETE, SELECT'

這個引數將在所有包括的語句型別上啟用審計。您甚至可能考慮為每種語句型別建立單獨的策略,這將允許您隨意地啟用和禁用策略 — 尤其是,控制審計線索的建立,以管理它們佔用的空間。不過,statement_type 引數預設情況下只審計 SELECT 語句。

在策略中新增新的引數之後,發出以下語句:

update accounts set balance = 1200 where balance >= 3000;

這將使一條記錄插入到 FGA_LOG$ 表中。注意這條記錄是由一個自動事務插入的;即使您回滾 update 語句,這條記錄也將存在。您可以從另一個會話來檢查線索是否存在。

select lsqltext from fga_log$;

LSQLTEXT
--------------------------------------------------------
update accounts set balance = 3100 where balance >= 3000 

該行還包括其它所有的相關詳細資訊(如表名稱、策略名稱和事務 ID)。

與觸發器方法相比較

那麼 FGA 能做什麼原來的基於觸發器的方法不能做的事情?

在 Oracle Database 10g 之前,DML 語句審計是在一個觸發器中進行的,類似於以下方式(注意:這不是真實的程式碼,只是一個代表性的示例):

CREATE TRIGGER XXXXX
ON Table
AFTER INSERT OR UPDATE OR DELETE
FOR EACH ROW
BEGIN
   INSERT INTO AUDIT_LOG
   Old Value, New Value, Time .....
END

觸發器捕獲舊的值和新的值,並填充 AUDIT_LOG 表。如果需要,還可以將它變為自動事務。最大的問題是觸發器是對每行觸發的,而不是每條語句一次。例如,以下語句:

update accounts set balance = 1200 where balance >= 3000;

對全部 10,000 條記錄觸發,在審計表中插入 10,000 行。這種方法可能嚴重地損害 update 語句的效能,甚至可能因審計線索中的空間問題而導致失敗。使用語句觸發器也無濟於事,因為它不能捕獲個別記錄的任何新的或舊的值。比較而言,在 FGA 方法中,只建立一條記錄,並且插入只在每條語句上執行一次,而不是每行一次 — 即使有的話,對效能的影響也很小。

在 FGA 中,您可以指定相關的列來限定審計線索僅在這些列被訪問時才建立。在觸發器中,通過使用觸發器定義的 WHERE,這種功能也可以實現。不過,其中存在一個非常重要的差異 — 在觸發器中,只有當列被修改時(而不是被訪問時)才檢查它們。在 FGA 中,無論何時列被訪問(無論它們被修改與否),審計就開始。這個特性使得 FGA 比觸發器具有更多的功能。

另一個優點是 FGA 工具的適用性。有時,在一個檢視上定義的 INSTEAD OF 觸發器在基表上更新檢視;另一個 INSTEAD OF 觸發器不能捕獲由其它的觸發器所作的修改,因此這些修改不能被記錄。然而,FGA 是建立在檢視或表的基礎上的,它能夠捕獲變化,而不論變化來自哪裡 — 使用者語句或觸發器。

那麼,是否存在觸發器比 FGA 更好的情況呢?可能有兩種情況:

  • 記住,FGA 通過一個自動事務來插入審計線索,這種事務在它自己的上下文中提交。當 DML 語句失敗或被回滾時,插入的線索記錄被回滾。如果使用者更新了一些東西但沒有提交,則不執行修改,但不管怎樣,將建立審計線索。這可能導致在審計線索中產生幾個虛假的實際專案 — 一種不希望出現的潛在情況。隨後使用通過閃回查詢捕獲的 SCN 號碼對錶進行分析將可能揭露這個問題,但這個過程可能非常複雜。但如果這種風險是不可接受的,那麼基於觸發器的方法將優於 FGA 成為首選。

  • FGA 記錄使用者發出的 SQL 語句和 SCN 號碼,但不記錄在修改之前和之後的值。必須使用一個單獨的工具來從表中通過閃回查詢取出這些值。因為閃回查詢依賴於 UNDO 段中包含的資訊(這些資訊是有限的),因此這個工具可能不會從過去很久的時間點上取出舊的值。基於觸發器的方法在源資料上捕獲變化,因此保證舊的值和新的值都有記錄。

在變化期間 FGA 的行為

資料始終在變化,因此它有可能變得適用於審計條件 — 雖然之前它不適用於審計條件,反之亦然。這個問題帶來了一些關於 FGA 在不同情況下的行為的有趣問題。考慮我們的例子,其中在 UPDATE 上已經定義了 FGA 策略,條件為 BALANCE >= 3000,審計列是 BALANCE。

第 1 種情況

之前:BALANCE = 1000

使用者發出:

update accounts set balance = 1200 where ACCOUNT_NO = ....

舊的和新的 balance 都小於 3,000,審計條件不滿足;因此這條語句將不會被審計。

第 2 種情況

之前:BALANCE = 1000

使用者發出:

update accounts set balance = 3200 where ACCOUNT_NO = ....

新的 balance 大於 3,000,審計條件滿足;因此這條語句將被審計。

第 3 種情況

之前:BALANCE = 3200

使用者發出:

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 結果為 FALSE),這條語句不會被審計。重要注意事項:假設該列一個大於 3,000 的預設值時,這條語句仍然不會被審計,即使插入行的 balance 列值大於 3000。

所有相關的列?

考慮在表 ACCOUNTS 上定義的一個策略,如下:

begin
   dbms_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,如果使用者發出以下語句:

select balance from accounts where account_no = 9995;

這條語句將被審計,因為 balance 列被選中,且餘額為 3,200,大於 3,000,滿足審計條件。不管這三個列中哪一個被選中,都將觸發審計。

在某些情況下,列的組合可能很重要,而不是某個特定的列。例如,如果一個使用者想查出在銀行的總餘額,她發出:

select sum(balance) from accounts;

這條查詢幾乎沒什麼害處;它不明確指出帳戶所有者和帳戶餘額。Acme Bank 安全策略可能不會要求審計這條查詢。不過,這條查詢

select balance from accounts where account_no = 9995

必須被審計;因為它明確地指定了一個帳戶。預設地,所有語句都被審計(無論使用了什麼樣的列組合)。這將建立大量不需要的審計線索專案,並可能帶來一些空間限制問題。為了限制它們,您可以指定僅當在查詢中使用了希望的列組合時才開始審計。當定義策略時,您可以使用一個新的引數:

audit_column_opts => DBMS_FGA.ALL_COLUMNS

這個引數將使策略僅當列 ACCOUNT_NO 和 BALANCE 在查詢中都被訪問時才建立審計線索專案。例如,以下查詢將產生一個審計線索專案。

select account_no, balance from accounts;

但這條查詢不會產生審計線索專案。

select account_no from accounts;

使用這個引數將把審計的數量限制在一個更易管理的大小。如果希望採用預設的行為 — 即任意列被選中時都進行審計,那麼您可以對同一引數的使用不同值。

audit_column_opts => DBMS_FGA.ANY_COLUMNS

捕獲賦值變數

利用 Oracle Database 10g,其它的有用資訊(如在查詢中使用的賦值變數的值)可以寫到常規的審計線索中。您可以通過設定初始化引數來執行這項任務

audit_trail = DB_EXTENDED

在 FGA 審計線索中,獲取賦值變數的值可能有意義也可能沒意義。如果您想要停止記錄這些值,您可以在 add_policy() 過程中使用另一個引數,如下:

audit_trail => DB

預設情況下,捕獲賦值變數,這個引數的值為 DB_EXTENDED。

全部綜合在一起

現在您已經瞭解了 Oracle Database 10g 中的幾個新的 FGA 引數,下面讓我們看看策略建立指令碼的宣告現在是什麼樣子。

下面我們定義對應四種語句型別的四種不同的策略。SELECT 語句的策略顯示如下,這裡我們選擇了不記錄賦值變數的值,並僅當列 ACCOUNT_NO 和 BALANCE 在查詢中都被使用時才觸發審計。

begin
   dbms_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 語句建立類似的策略。它們可以隨意地啟用或禁用。

結合常規審計和細粒度審計

在 Oracle Database 10g 中,常規審計也得到了巨大的改進。通過 AUDIT 命令執行常規審計,它現在能夠捕獲大量其它有用的資訊,例如:

  • 擴充套件的細粒度時間戳記
  • 作業系統程式 ID
  • 事務識別符號(當審計線索被一個資料修改事務(如通過一次更新)建立時,事務 ID 在此時被記錄,記錄的事務 ID 在之後可以和檢視 DBA_TRANSACTION_QUERY 結合來識別確切的語句、它的撤消 SQL、行 ID 等等)
  • SQL 語句正文
  • 賦值變數的值
  • 修改時的 SCN。

您可以看到,在內容和功能方面,常規審計類似於細粒度審計。然而,作為一個資料庫管理員,您有興趣知道所有的審計專案,而不只是一個審計專案。一個新的檢視,DBA_COMMON_AUDIT_TRAIL,結合了常規線索和 FGA 線索。用以下查詢來檢查它們二者:

select * from dba_common_audit_trail;

這個檢視結合了 DBA_AUDIT_TRAIL 和 DBA_FGA_AUDIT_TRAIL,擁有來自每個檢視的相關資訊。這個檢視從資料字典中建立,如下所示。

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_CPU
  from DBA_AUDIT_TRAIL
UNION ALL
select '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, Null
  from DBA_FGA_AUDIT_TRAIL

FGA 和常規審計:差異

如果標準審計和細粒度審計在 Oracle Database 10g 中是類似的,您可能要問,在什麼情況下,FGA 將是更好的選擇?好的,讓我們研究一下它們的差異。

  • 標準審計必須用引數 AUDIT_TRAIL 在資料庫級啟用。這個引數不是動態的;您必須重啟資料庫來使其生效。相比而言,FGA 不需要任何引數修改。

  • 一旦被設定在一個物件上,標準審計將保持在那裡。要解除它,您必須用 NOAUDIT 命令刪除審計選項。這可能很不方便,因為在一個表上丟棄審計選項也將丟棄後設資料資訊。然而,FGA 可以臨時禁用和啟用,不丟失任何後設資料資訊。

  • FGA 只能夠處理四種型別的語句:SELECT、INSERT、UPDATE 和 DELETE。相比而言,常規審計可以處理其它許多語句和許可權,甚至會話連線和斷開。

  • 標準審計每次會話只建立一條記錄(按會話)或每次訪問物件建立一條記錄(按訪問)這種佔用資源很少的方式對於控制審計線索表中的空間非常重要。FGA 並不是同樣節省資源;它每次訪問執行一次 — 使得線索更大。

  • 通過記錄線索,標準審計可以用來檢測任何中斷企圖,如果企圖沒有成功,則將產生錯誤程式碼。而 FGA 不能。

  • 標準審計可以寫資料庫表或 OS 檔案。後者在審計員(不是資料庫管理員)能夠訪問線索時非常有用。在 Windows 下,非資料庫審計線索記錄在事件日誌中,並且可以用不同的方式對其進行訪問。這個選項保護了審計線索的完整性。然而,FGA 日誌僅寫到資料庫表 FGA_LOG$ 中。您可以在 FGA 中建立使用者自定義的審計處理程式來寫 OS 檔案,但它們的完整性不能保證。

  • 標準審計可以設定用於預設物件。當表是在執行期建立時,這個功能變得極為有用:預設的審計選項允許沒有資料庫管理員干預的審計。這在 FGA 中是不可能的,使用者必須在一個現有的表上建立策略,上述的情況只能在表已建立之後才可能發生。

  • 在 FGA 中,審計更加靈活 — 僅當訪問某些列,當某個特定的條件為真時等等。這種多功能性在您需要控制線索的增長時非常方便。

  • 在 FGA 中,SQL 賦值變數預設被捕獲。在常規審計中,必須把初始化引數 audit_trail設為 db_extended,以啟用這一功能。

  • 許可權差異:常規審計需要審計系統或語句許可權;FGA 只需要 dbms_fga 程式包上的執行許可權。

通過上面的比較,您將瞭解為什麼可以證明 FGA 在某些情況下很有用。利用 Oracle Database 10g 中的增強的常規審計特性,一些以前認為不可能的任務 — 例如捕獲賦值變數的值 — 變得十分容易。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/756652/viewspace-242218/,如需轉載,請註明出處,否則將追究法律責任。

相關文章