應用程序用戶問題

上篇文章解釋了如何構建一個 FGA 系統,從而在表 FGA_LOG$ 中記錄發出查詢的數據庫用戶。在數據庫用戶映射到一個物理用戶的情況下,這一方法非常有效。但是,在有些情況下(如在基于 web 的應用程序中),應用服務器使用固定的用戶 id(如 APPUSER)連接到數據庫。應用程序用戶由應用程序驗證。例如,用戶 SCOTT 連接到應用程序,應用程序驗證用戶,然后使用用戶 id APPUSER 連接到數據庫。如果在此環境中使用了 FGA,FGA 將顯示用戶為 APPUSER 而不是 SCOTT。同樣,另一個選擇數據的應用程序用戶 JANE 也將被記錄為 APPUSER 而不是 JANE。由于記錄的用戶名不是實際的用戶,審計沒有發揮作用。

立刻迸入腦海里的解決方案是在數據庫中創建應用程序用戶,讓應用程序使用用戶 id 和口令連接到數據庫。例如,在上述示例中,用戶 SCOTT 和 JANE 將是數據庫中的用戶,無需存在一個名為 APPUSER 的用戶。這一方法既簡單又安全,因為數據庫驗證用戶,并且不管連接采用何種方式,用戶始終保持不變。

但是在該方法下,所有的用戶都必須在數據庫中創建,這將導致管理極其困難—尤其當用戶數量達到幾千人(這在 web 應用程序中很常見)。此外,用戶必須記住他們在不同地方的用戶名和口令,這一麻煩正是一次性登錄存在的全部理由。盡管使用 Oracle Advanced Security Option(ASO,也稱為高級聯網選項或者 ANO)以及 Oracle Internet Directory 可以解決這一問題,但是對于大多數網站,此解決方案不可行。

在 web 應用程序中,連接池的概念還需要使用一個普通的用戶 id。如圖 1 所示,應用服務器使用用戶 APPUSER 創建了幾個與數據庫的連接。當應用程序用戶(如 SCOTT)需要涉及數據庫的服務時,應用程序使用與數據庫的一個連接來完成請求。這一模型可以使用幾個連接支持許多用戶,因此受到 web 應用程序設計師的歡迎。但需要重申的是,這一方法不會在 FGA 中記錄正確的用戶名。

 

圖 1

 

使用應用程序用戶 id 的理由非常充分。因此,理想的解決方案是在 FGA 框架中使用應用程序用戶 id,而不是繞過該需求。

客戶端標識符

Oracle9i 引進了客戶端標識符(一個可以作為會話屬性的值)的概念。任何值都可以放入該屬性中,在我們的情況中,可以使用它來代表實際的用戶名,如 JANE。盡管數據庫用戶名被記錄為 APPUSER 或其它名字,客戶端標識符可以存放值 JANE。

可以將會話的客戶端標識符設置為某個值,方法是調用 Oracle 提供的 API dbms_session.set_identifier。下列語句設置了會話中的標識符 SCOTT:

EXECUTE DBMS_SESSION.SET_IDENTIFIER ('SCOTT')

 

設置完以后,此標識符將在該會話的 V$SESSION 視圖中顯示。

SELECT CLIENT_IDENTIFIER
FROM V$SESSION
WHERE AUDSID = USERENV('SESSIONID');

 

顯示的值為 SCOTT,正如前面所設。那么,該值的重要性體現在哪里?除了出現在 V$SESSION 視圖中,此信息還會顯示在 FGA 表 FGA_LOG$ 以及隨后的 DBA_FGA_AUDIT_TRAIL 視圖的 CLIENT_ID 列中,如下所示:

SELECT DB_USER, CLIENT_ID FROM DBA_FGA_AUDIT_TRAIL;

 

盡管 DB_USER 列顯示了數據庫用戶,真正的應用程序用戶(如果放在標識符中)可以在 FGA 跟蹤中捕獲。當審計應用程序用戶時,這是一個需要理解和應用的非常重要的概念。

客戶端標識符還出現在常規的審計跟蹤中,而不僅僅出現在細粒度的審計跟蹤中。因此,在各種審計情況下(從常規類型到高級的細粒度類型),這個值都提供缺少的鏈接來表示實際的用戶。在常規的審計跟蹤中,表 AUD$ 在列 CLIENTID 中記錄了客戶端標識符(如果在會話中已設置)。該值顯示在相關的視圖中,如列 CLIENT_ID 中的 DBA_AUDIT_TRAIL。

令人感到困難的是如何正確地設置這一值。請記住,在一個啟用 web 且具有連接池的應用程序中,數據庫會話服務于許多用戶會話—在會話之初僅設置一次值沒有作用。此外,應用程序必須在每次調用數據庫之前設置客戶端標識符,從而 FGA 能夠看到真正的應用程序用戶 id。當另一個應用程序線程重用數據庫會話時,標識符被設置為另一個用戶 id,標識 FGA 跟蹤中的該名用戶。

另一種方法是設置一個 cookie,并使用該值設置客戶端標識符。這種方法更安全,因為 cookie 可以包括其它的驗證信息,而通過常規的會話根本不可能設置這些信息。然后,可以正確地解碼標識符中的值,獲得真正的用戶名;但是驗證信息為該值添加了一個數據完整性組件。

應用程序環境

使用客戶端標識符有它的優點,但也存在嚴重的安全威脅:這種設置假定用戶將值設為真正的用戶 id,但這一點無法得到保證。惡意攻擊的用戶可以連接然后將該值設為不同的用戶 id,嚴重地破壞審計跟蹤的真實性。在 web 應用程序中,使用 cookie 存儲客戶端標識符使得破壞更困難(如果不是不可能);但是在普通的應用程序中,僅僅使用客戶端標識符,安全性可能不盡人意。我們需要一種更安全的方法來捕獲審計跟蹤中的應用程序用戶。

進入解決方案:應用程序環境.應用程序環境類似于會話變量;一旦設置了,任何時候都可以在會話中訪問它們。可以在另一個會話中設置一個不同的值,而在整個會話中都看不到這個值。環境具有的屬性類似于表的列;但與表不同的是,環境不是片段對象,屬性可以在運行時而不是設計時定義。

可以使用下列 SQL 創建應用程序環境:

create context my_app_ctx using set_my_app_ctx;

 

注意,子句 using set_my_app_ctx 意味著環境中的屬性只能通過名為 set_my_app_ctx 的過程來操作,該過程定義如下:

create or replace procedure set_my_app_ctx
(
p_app_user in varchar2 := USER
)
is
begin
dbms_session.set_context('MY_APP_CTX','APP_USERID', p_app_user);
end;

 

此過程通過調用 dbms_session.set_context API,簡單地將屬性 APP_USERID 設置為輸入參數傳遞的值。因此,如果用戶直接調用此 API,其結果會如何呢?

SQL> exec dbms_session.set_context('MY_APP_CTX','APP_USERID', 'JUNE')
BEGIN dbms_session.set_context('MY_APP_CTX','APP_USERID', 'JUNE'); END;
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "SYS.DBMS_SESSION", line 78
ORA-06512: at line 1

 

注意錯誤 ORA-01031:insufficient privileges 有點令人誤解。用戶的確對 SYS.DBMS_SESSION 有執行權限,但是通過調用它來設置環境屬性是違法的,因此出現了錯誤。但是,當用戶調用受信任的過程來設置環境屬性:

SQL> execute set_my_app_ctx ('AAAA')
PL/SQL procedure successfully completed.

 

設置成功了。因為環境屬性只能通過它的過程(正確叫法是 受信任的過程)來設置。這是應用程序環境一個非常重要的屬性,將在 FGA 中得到使用。

一旦設置了環境屬性,可以通過調用函數 SYS_CONTEXT 來檢索它。在上述代碼中設置完環境后,可以通過下列語句來查看環境:

select sys_context('MY_APP_CTX','APP_USERID') from dual;

 

該語句返回屬性值。如果可以通過安全的方式設置環境,則可以利用環境來設置客戶端標識符。

基于我們現有的知識,以下是可能的解決方案:

  • 應用程序執行過程代碼,該代碼自動地將應用程序環境設置為正確的值。在上述示例中,使用了用戶 id 的環境屬性,但另一個屬性—如用戶的角色—可能已經被使用了。可以在一個環境中定義多個屬性。可以將屬性作為啟用的角色使用。受信任的過程可以包括各種類型的安全檢查,從而使得它安全且真實可信。如果安全檢查失敗了,則不能設置所需的角色。因此,即使用戶可以使用 APPUSER 帳號成功地登錄,他也不能夠操作數據,因為沒有啟用適當的角色。注意,角色必須經過過程認證,而不能是普通的角色。這種角色由命令 CREATE ROLE USING 創建;用戶通過調用 而不是 SET ROLE 命令啟用角色。

     

     

  • 此過程也設置客戶端標識符,因此沒有必要授予公眾對 dbms_session 的執行權限,即使對此用戶也沒有必要。由于用戶沒有權限調用 API,他們不能直接設置客戶端標識符—客戶端標識符將被自動設置,并且傳遞到細粒度的審計跟蹤。

 

這一方法可以使用用戶定義的審計跟蹤得到進一步的完善。其中客戶端標識符可以被設置為從應用程序環境中檢索到的值。我們將在本系列的第三部分(以及最后一部分)中討論該方法。

用戶看到的狀況如何呢?

細粒度的審計跟蹤記錄用戶連同綁定變量的值(如果存在)一同輸入的實際語句。下面是從跟蹤中可以捕獲的一條典型語句:

select balance from accounts
where acct_no = 10034;

 

假設這一事務處理發生在 10:00AM,而現在是 11:00AM。在這種情況下,帳戶余額可能已經更新了。如果審計員(或者 DBA)決定查看用戶在那一時刻看到的實際情況,列的當前值可能沒有反映準確的信息。在工業間諜的情況中,或者要建立動機或模式,用戶非常有必要看到確切的數據。即使 FGA 沒有捕獲該時刻的準確數據,我們也可以使用跟蹤中捕獲的另一條信息看到該數據。

在本系列的第 1 部分中,我們看到了視圖 DBA_FGA_AUDIT_TRAIL 的結構。該視圖記錄了與會話和用戶相關的幾條關鍵信息。此處的相關列是 SCN,它記錄了生成跟蹤時的系統更改號。使用閃回查詢,我們可以重建該點時刻的數據。假設審計跟蹤中 SCN 的值為 123456,我們可以如下所示進行查詢:

select balance from accounts as of SCN 123456
where acct_no = 10034;

 

SCN 123456 的子句將從表中返回該點時刻而不是現在的余額,這正是我們所需要的。

由于閃回局限于撤消保留時段,在該時段外發生的事務會丟失。但是,審計員可能尋找自事件發生的跟蹤,因此,使用閃回僅捕獲重要的列,執行一次定期的審計收集是比較謹慎的做法。



開心過好每一天。。。。。