应用程序用户问题

上篇文章解释了如何构建一个 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 的子句将从表中返回该点时刻而不是现在的余额,这正是我们所需要的。

由于闪回局限于撤消保留时段,在该时段外发生的事务会丢失。但是,审计员可能寻找自事件发生的跟踪,因此,使用闪回仅捕获重要的列,执行一次定期的审计收集是比较谨慎的做法。



开心过好每一天。。。。。