在大型的信息系统开发中,我们往往选择功能强大的数据库系统作为应用层的数据存储,除了支撑业务系统的正常运行外,还要求数据库系统有较高的可靠性、保密性、可控性和可跟踪性,对数据库系统的各种操作是在有监控的条件下进行的,同时,对重要数据的操作也要保留历史痕迹,这样,当出现了重大的涉密业务办理失误,需要进行责任追查认定时,数据库级别的审计功能可以有效地配合应用系统层审计记录,进一步提高审计的强度,从而为事后追踪和责任认定提供有力的审计证据。同时,应用系统层的某些审计功能的实现也需要数据库审计特性的辅助来实现。
Oracle 数据库系统被应用于很多大型的信息系统中,为应用系统提供了良好的数据库存储支持和广泛的安全特性以保护用户的信息免受未经授权的访问及有意或无意的破坏。这种安全性是在用户到用户,权限到权限的基础上通过授予或撤消权限来提供的,并且是附加于但又独立于用户的计算机系统本身已有的安全机制之上。在实现了权限分配的基础上,应用中又面临着实时跟踪被使用的系统资源与数据库资源,监测用户对数据库的行为的问题,这就是大型数据库管理系统所必需的审计功能。
从Oracle 9i开始,引入了一个新的安全特性——Auditing(Oracle 9i审计特性)。Oracle 9i审计特性为我们提供了监视和记录数据活动的功能,通常用于监视重要的数据库活动和收集特定的数据库活动信息。利用该特性,我们可以实现对数据库系统的操作进行记录以及对特定重要业务数据表的控制,甚至可以实现应用系统的操作与数据库动作的关联。
默认情况下,为了提高数据库系统的性能,审计特性是关闭的。如果需要开
启审计功能,需要设置audit_trail参数的值为 ‘DB’,该操作可以通过管理控制台来实现,也可以通过修改初始化参数文件init.ora实现,但是即使这样,我们仍旧不能做到对审计特性的即时开关,因为audit_trail是一个静态参数,需要在下一次数据库系统重新启动后才能生效。修改该参数并重新启动数据库后,可以在通过如下命令来查询审计特性是否已开启:
SQL> show parameter audit_trail;
NAME TYPE VALUE
------------------------------------ ----------- ------------
audit_trail string DB
audit_trail 参数的值可以设置为以下几种:
1.
NONE:不开启审计功能
2.
DB:开启审计功能,并将审计记录保存在数据库系统提供的审计视图内,要求用于审计功能实现的视图已经创建。
3.
OS:审计记录写入一个操作系统文件。
4.
TRUE:与参数DB效果等同
5.
FALSE:不开启审计功能。
SPFILE
服务器端参数文件
Oracle 9i提供了一个二进制服务器参数文件(spfile)来管理初始化参数,这是一个另人激动的新特性。通过spfile,我们就可以使用alter system或者alter session命令动态地改变所有的参数,尽管有些静态参数不能够马上生效,但是可以修改到spfile中,将在数据库下次重新启动后生效。
可以通过如下方式建立SPFILE:
SQL> startup pfile=‘C:\Oracle\admin\orcl\pfile\init.ora';
SQL> create spfile from pfile;
这样,SPFILE就建立成功了,但是不能以同样的方式指定spfile来启动数据库,Oracle 9i提供了一种变通的方法,即可以创建一个包含spfile参数的pfile文件,指向spfile,如下是一个pfile文件的内容:
这样,我们在启动时指定pfile,实际上就实现了以SPFILE文件启动数据库的操作,同时,在该pfile文件中,还可以指定其他的参数,如果出现与SPFILE中重复的参数设置,那么,后出现的参数设置将覆盖先前的设置。
采用如上方式启动数据库后,你就可以使用alter system命令来改变任何一个初始化参数。
SQL> alter system set audit_trail = ‘DB’ scope=spfile;
这里,需要对重要的scope参数引起注意。
scope参数具有三个值:
1.
spfile: 在spfile中改变一个参数而不影响当前的实例。
2.
memory:仅将改变应用于当前实例。
3.
both:立即执行改变,并永久地使用改变。
在使用spfile启动数据库后,我们就可以在系统应用层通过业务逻辑来实现
对audit_trail参数的修改,该修改将在下一次重新启动数据库后生效,从而,我们可以不手动修改init.ora文件,并在应用系统层实现对审计开关的控制。如下所示将在数据库重新启动后关闭审计开关:
PreparedStatement ps = db.getConnnection().prepareStatement(
PreparedStatement ps = db.getConnnection().prepareStatement(
"alter system set audit_trail='NONE' scope=spfile");
ps.execute();
如何实现
审计
Oracle审计特性提供了三种级别的审计,分别是语句级、权限级和实体级,同时,我们还可以配合使用触发器来实现特定的细粒度的审计功能实现,以到达互补的效果,提供更全面和强有力的审计证据支持。
l
语句级审计
语句级审计表示只审计某种类型的SQL语句,可以审计某个用户,也可以审计所有用户的SQL语句,其语法如下:
SQL>Audit SQL语句或选项
[by 用户名] -- 表示只审计指定用户的 SQL 语句,不审计其他用户的 SQL 语句
[by session/access] --by session: 每个会话相同语句只审计一次,系统默认;
by access: 每次都将审计
Whenever [NOT] Successful;-- 只审计(不)成功的语句
[by 用户名] -- 表示只审计指定用户的 SQL 语句,不审计其他用户的 SQL 语句
[by session/access] --by session: 每个会话相同语句只审计一次,系统默认;
by access: 每次都将审计
Whenever [NOT] Successful;-- 只审计(不)成功的语句
SQL语句或选项参数不需要写出全部的SQL语句,只需要写出语句的选项即可,这样可以代表某一类的SQL语句。例如:
audit table by bjmiadmin by access
当用户执行Create Table;Drop Table;Truncate Table等与table相关的操作时,系统会自动记录这些过程,将其保存在相应的数据字典中。我们可以通过查询数据字典DBA_STMT_AUDIT_OPTS来查看具体的语句级审计实施细节。
如果我们不需要再进行审计,可以通过Noaudit命令取消审计,如:
noaudit table by bjmiadmin by access
l
权限级审计
权限级审计表示只审计某一系统权限的使用状况,可以审计某个用户,也可以审计所有用户,其语法如下:
SQL>Audit
权限名称
[by 用户名] -- 表示只审计指定用户的SQL语句,不审计其他用户的SQL语句
[by session/access] --by session: 每个会话相同语句只审计一次,系统默认;
by access: 每次都将审计
Whenever [NOT] Successful; -- 只审计(不)成功的语句
[by 用户名] -- 表示只审计指定用户的SQL语句,不审计其他用户的SQL语句
[by session/access] --by session: 每个会话相同语句只审计一次,系统默认;
by access: 每次都将审计
Whenever [NOT] Successful; -- 只审计(不)成功的语句
权限名称包含了大部分的对数据库对象的DDL操作,如alter,create,drop等等。例如:
audit delete any table
该命令将对任何用户的删除表的操作进行记录。如果想知道当前对哪些用户进行了哪些权限级别的审计,可以通过查询数据字典DBA_PRIV_AUDIT_OPTS来了解细节。
如果不需要再对用户进行系统权限的审计,那么可以使用noaudit命令取消对用户所进行的权限审计,如:
noaudit delete any table
l
实体级审计
实体级审计用于监视所有用户对某一指定用户表的存取状况,实体级审计是不分用户的,其重点关注的是哪些用户对某一指定用户表的操作,其语法如下[16]:
SQL>Audit
实体选项 ON Schema 实体名称
[by session/access] --by session:每个会话相同语句只审计一次,系统默认;
by access:每次都将审计
Whenever [NOT] Successful;--只审计(不)成功的语句
[by session/access] --by session:每个会话相同语句只审计一次,系统默认;
by access:每次都将审计
Whenever [NOT] Successful;--只审计(不)成功的语句
各选项范围与语句级及权限级审计相同,例如:
audit update on bjmiadmin.deptinfo whenever successful
该命令将对bjmiadmin.deptinfo的更新操作进行记录。如果想知道当前对哪些用户的哪些实体进行了实体级审计及审计的选项,可以通过查询数据字典DBA_OBJ_AUDIT_OPTS来了解实施细节。
如果不需要再对用户进行系统权限的审计,那么可以使用noaudit命令取消对实体审计,如:
no
audit update on bjmiadmin.deptinfo
l
触发器
触发器是一种特殊的过程,与普通的过程不同的是,触发器不需要显示调用,而是当某些事件发生时,由数据库系统自动执行。触发器的构成包括[17]:
触发事件:引起触发器被触发的事件,如insert、update等DML语句或者create、alter、drop等DDL语句,数据库系统事件或者用户事件等等。
触发条件:由WHEN子句指定的一个逻辑表达式,只有当该表达式为TRUE时,遇到触发器事件才会自动执行触发器。
触发对象:包括表、视图、模式和数据库。
触发操作:触发器定义的过程。
在BJMI电子政务安全审计系统中,我们综合利用了多种触发器类型,如DDL触发器(对所有用户的DDL操作进行审计)、DML触发器(对重要的表和视图的DML操作进行审计,保存数据的历史和更新)、系统事件触发器(记录系统启动、退出或异常错误等)、用户事件触发器(用户登录系统或退出系统的动作)等。如下是实现系统事件审计的触发器
CREATE OR REPLACE TRIGGER BJMIADMIN.AUDIT_DB_STARTUP_TRIGGER
AFTER STARTUP ON DATABASE
BEGIN
INSERT INTO BJMIADMIN.AUDIT_DBLOG
VALUES(SYSDATE,'STARTUP');
END;
数据库关闭触发器:
CREATE OR REPLACE TRIGGER BJMIADMIN.AUDIT_DB_SHUTDOWN_TRIGGER
BEFORE SHUTDOWN ON DATABASE
BEGIN
INSERT INTO BJMIADMIN.AUDIT_DBLOG
VALUES(SYSDATE,'SHUTDOWN');
END;
通过以上触发器的配置,我们可以得到数据库系统的启动和关闭动作的日志,对数据库系统的运转情况可以实现历史查看。这些历史记录将在应用系统层提供给审计管理员进行查看。
审计结果
的使用
针对采取的审计策略不同,审计日志也应当分别采用不同的存储策略进行存储。采用Oracle 9i审计特性实现的审计功能,如语句级、权限级和实体级审计记录将保存在系统视图里;利用触发器实现的审计功能获取的日志可以保存在自定义的数据库表中。
将审计结果都将保存在数据库系统中,具有良好的格式,可以对审计日志进行分析和挖掘,非常容易维护,同时,我们可以利用数据库系统的安全性对日志进行保护和管理。当然,考虑性能原因,我们可以进行自定义的审计实现,只审计重要的业务表,而不是对所有的表都进行审计,这就要求对需求的透彻分析从而确定优良的数据库审计方案。
Oracle 9i定义了格式良好的审计视图来保存开启审计功能后产生的审计记录。这些视图包括:AUD$,DBA_AUDIT_OBJECT, DBA_AUDIT_TRAIL, DBA_AUDIT_SESSION等。系统定义的视图为我们提供了详细的审计信息,如:SESSIONID,ENTRYID,STATEMENTID,USERID,USERHOST,TERMINAL等,包含了数据库会话ID,客户端详细信息,时间戳等等,我们可以从中选择适应于审计需求的信息。
自定义审计主要根据特定的需要而编写触发器来实现,如果我们需要对系统事件,如数据库系统的启动和关闭,可以编写如下的触发器来实现,当然,为了存储审计日志,我们需要建立数据库表来存储日志。入下是建立用于存储数据库系统启动/关闭日志的字定义审计表,该表的审计日志数据由上文的触发器而得到:
CREATE TABLE BJMIADMIN.AUDIT_DBLOG(
TIME DATE,--登录时间
ACTION VARCHAR2(20)--动作
)
TABLESPACE "BJMIGYJ" ;--表空间
自定义审计表具有很大的灵活性,我们可以根据审计需求,有针对性地设计审计表,配合触发器来得到审计日志。
如何实现应用层操作和数据库动作的关联
通过研究Oracle数据库系统的
SYS_CONTEXT
来关联应用层动作和数据库的动作。USERENV是Oracle提供的一个命名空间,用来保存当前的会话信息。我们在进行审计日志的采集的同时,可以通过Oracle数据库系统提供的SYS_CONTEXT
('USERENV', 'SESSION_ID')来得到数据库的会话ID,然后将数据库会话ID也作为审计日志的一个列属性进行存储,这样,应用层的日志就存储了数据库会话ID。而我们的数据库层审计,会话ID也是一个必不可少的审计信息,这样,通过会话ID的关联,我们就可以把应用层的动作和数据库系统的相应数据处理动作关联起来,这也更加增强了审计的强度。
另外,我们还可以通过以下方式进行关联——使用CLIENT_IDENTIFIER。
应用程序上下文是一组可用于数据库会话的名字/值对。Oracle9i有预定义的应用程序上下文名字空间USERENV,它含有用户会话信息,包括预定义的属性CLIENT_IDENTIFIER,我们可以稍加变更,将它用于保持Web用户标识符。
从servlet或Enterprise JavaBeans (EJB)会话bean,应用程序代码将从Web请求检索用户名,然后调用内部PL/SQL过程设置CLIENT_IDENTIFIER:
String userName = request.getRemoteUser();
(set up the JDBC connection)
PreparedStatement ps = conn.prepareCall(
"begin dbms_session.set_identifier(?);
end;");
ps.setString(1, username);
ps.execute();
我们可以通过SELECT sys_context('userenv', 'client_identifier') FROM dual;来得到我们设定的Web用户标识符。但是,这种方法不够安全,因为任何人都能设置这个上下文值,因此必须借助额外的安全性措施,如细粒度的访问控制和安全的应用程序角色等,同时,应用程序还应在将数据库连接返回给连接池之前清除CLIENT_IDENTIFIER属性。
结论
本篇文章主要通过课题案例研究了Oracle数据库系统的审计特性,为数据库管理人员提供了一些实施数据库系统层审计的方案,同时,对应用系统的开发人员实现应用层的安全审计具有重要的借鉴意义。Oracle的审计特性可以帮助开发人员实现一个完善的安全审计子系统,从而保证整个系统的安全体系的完善,为其提供强大的抗抵赖服务。
本文转自 august 51CTO博客,原文链接:http://blog.51cto.com/august/57344,如需转载请自行联系原作者