dba

109.3  数据库授权方法

一旦使用数据库验证了用户,下一步就是确定用户可以有权访问或使用的对象类型、权限和资源。本节中将介绍配置文件控制管理密码的方式,还将介绍配置文件在各种类型的系统资源上添加限制的方式。

此外,本节将讨论Oracle数据库中两种类型的权限:系统权限和对象权限。这两种权限都可以直接赋予用户,或者通过角色间接赋予用户,这是另一种在将权限赋予用户时可以简化DBA工作的机制。

本节的末尾将概述Oracle的虚拟专用数据库(VPD)特性,以及如何使用此特性将其用于对如下情况提供更精确的地控制:用户根据赋予自己的一组DBA定义的证书来可以查看表的某些哪些部分。为了帮助使这一概念更加清晰,我们将完整地实现一个VPD。

109.3.1  配置文件的管理

看起来似乎总是不会有足够的CPU功率或磁盘空间或I/O带宽来运行用户的查询。因为所有这些资源本来就是有限的,Oracle提供了一种机制来控制用户可以使用多少资源,Oracle配置文件就是提供这种机制的指定资源限制集。

此外,配置文件可用作授权机制来控制如何创建、重用和验证用户密码。例如,可能希望实施最小的密码长度,同时需要密码中至少出现一个大写字母和一个小写字母。本节中将讨论配置文件如何管理密码和资源。

1. CREATE PROFILE命令

create profile命令有双重用途。可以创建配置文件,将用户的连接时间限制为120分钟。

create profile lim_connect limit

connect_time 120;

类似地,可以限制在锁定账户之前注册登录可以连续失败的次数:

create profile lim_fail_login limit

failed_login_attempts 8;

或者,可以将这两种类型的限制合并结合在一个配置文件中:

create profile lim_connectime_faillog limit

connect_time 120

failed_login_attempts 8;

Oracle如何响应超出的一种资源限制取决于限制的类型。当到达一个连接时间限制或空闲时间限制(如CPU_PER_SESSION)时,回滚进行中的事务,并且取消会话连接。对于大多数其他的资源限制(如PRIVATE_SGA),回顾回滚当前的事务,将一个错误返回给用户,并且用户可以选择提交或回滚事务。如果操作超出某个调用的限制(如LOGICAL_READS_PER_ CALL),则中断该操作,回滚当前的语句,并且将一个错误返回给用户。事务的剩余部分保持不变,然后,用户可以回滚、提交或尝试在不超出语句限制的情况下完成事务。

Oracle提供了DEFAULT配置文件,如果没有指定其他的配置文件,则将该配置文件应用于任何新的用户。下面针对数据字典视图DBA_PROFILES的查询显示了DEFAULT配置文件的   限制:

SQL> select * from dba_profiles

  2      where profile = 'DEFAULT';

PROFILE          RESOURCE_NAME               RESOURCE LIMIT

------------- -----------------------     -------- -------------

DEFAULT          COMPOSITE_LIMIT              KERNEL   UNLIMITED

DEFAULT          SESSIONS_PER_USER           KERNEL   UNLIMITED

DEFAULT          CPU_PER_SESSION              KERNEL   UNLIMITED

DEFAULT          CPU_PER_CALL                KERNEL   UNLIMITED

DEFAULT          LOGICAL_READS_PER_SESSION KERNEL   UNLIMITED

DEFAULT          LOGICAL_READS_PER_CALL      KERNEL   UNLIMITED

DEFAULT          IDLE_TIME                     KERNEL   UNLIMITED

DEFAULT          CONNECT_TIME                KERNEL   UNLIMITED

DEFAULT          PRIVATE_SGA                   KERNEL   UNLIMITED

DEFAULT          FAILED_LOGIN_ATTEMPTS       PASSWORD 10

DEFAULT          PASSWORD_LIFE_TIME          PASSWORD 180

DEFAULT          PASSWORD_REUSE_TIME       PASSWORD UNLIMITED

DEFAULT          PASSWORD_REUSE_MAX          PASSWORD UNLIMITED

DEFAULT          PASSWORD_VERIFY_FUNCTION  PASSWORD NULL

DEFAULT          PASSWORD_LOCK_TIME          PASSWORD 1

DEFAULT          PASSWORD_GRACE_TIME       PASSWORD 7

16 rows selected.

SQL> select * from dba_profiles

2       where profile = 'DEFAULT';

 

PROFILE          RESOURCE_NAME                     RESOURCE LIMIT

--------------- -------------------------------- -------- ------------

DEFAULT          COMPOSITE_LIMIT                   KERNEL    UNLIMITED

DEFAULT          SESSIONS_PER_USER                 KERNEL    UNLIMITED

DEFAULT          CPU_PER_SESSION                   KERNEL    UNLIMITED

DEFAULT          CPU_PER_CALL                      KERNEL   UNLIMITED

DEFAULT          LOGICAL_READS_PER_SESSION         KERNEL    UNLIMITED

DEFAULT          LOGICAL_READS_PER_CALL            KERNEL    UNLIMITED

DEFAULT          IDLE_TIME                         KERNEL   UNLIMITED

DEFAULT          CONNECT_TIME                      KERNEL   UNLIMITED

DEFAULT          PRIVATE_SGA                       KERNEL    UNLIMITED

DEFAULT          FAILED_LOGIN_ATTEMPTS             PASSWORD  10

DEFAULT          PASSWORD_LIFE_TIME                PASSWORD  UNLIMITED

DEFAULT          PASSWORD_REUSE_TIME               PASSWORD  UNLIMITED

DEFAULT          PASSWORD_REUSE_MAX                PASSWORD UNLIMITED

DEFAULT          PASSWORD_VERIFY_FUNCTION          PASSWORD  NULL

DEFAULT          PASSWORD_LOCK_TIME                PASSWORD  UNLIMITED

DEFAULT         PASSWORD_GRACE_TIME              PASSWORD UNLIMITED

 

DEFAULT配置文件中唯一真正的约束将锁定账户前连续不成功的注册登录尝试数量(FAILED_LOGIN_ATTEMPTS)限制为10,将必须改变密码前此密码可以使用的天数 (PASSWORD_LIFE_TIME)设置为180。此外,没有启用任何密码验证功能。

2. 配置文件和密码控制

表109-4中是密码相关的配置文件参数。按照天数指定所有时间单位(例如,为了以分钟为单位指定这些参数,可以将其除以1440):

SQL> create profile lim_lock limit password_lock_time 5/1440;

Profile created.

SQL> create profile lim_lock limit password_lock_time 5/1440;

在该示例中,在指定数量的注册登录失败指定的次数后,账户将只锁定5分钟。

表109-4  密码相关的配置文件参数

密 码 参 数

说    明

FAILED_LOGIN_ATTEMPTS

锁定账户前失败的注册登录尝试的数量次数

PASSWORD_LIFE_TIME

在必须改变密码前可以使用该密码的天数。如果没有在PASSWORD_GRACE_TIME中进行改动,则必须在允许注册登录前改变该密码

PASSWORD_REUSE_TIME

用户在重新使用密码前必须等待的天数;该参数和PASSWORD_REUSE_MAX结合起来使用

PASSWORD_REUSE_MAX

在可以重用密码前必须进行的密码改动次数;该参数和PASSWORD_REUSE_TIME结合起来使用

PASSWORD_LOCK_TIME

在FAILED_LOGIN_ATTEMPTS尝试后锁定账户的天数。在这个时间周期后,账户自动解除锁定

PASSWORD_GRACE_TIME

在多少天之后必须改变到期密码必须改变后的天数。如果没有在这个时间周期内进行改动,则账户到期,并且必须在用户可以成功注册登录之前改变该密码

PASSWORD_VERIFY_FUNCTION

PL/SQL脚本,用于提供高级密码验证例程。如果指定为NULL(默认值),则不执行任何密码验证

参数值unlimited表示没有限制可以使用的给定资源数量。dDefault表示该参数从DEFAULT配置文件中获得它的值。

参数 password_reuse_time和password_reuse_max必须同时使用。设置其中一个参数,而不设置另一个参数,则不会有任何作 用。在下面的示例中,创建一个配置文件,将password_reuse_time设置为20天,而将password_reuse_max设置为5:

create profile lim_reuse_pass limit

password_reuse_time 20

password_reuse_max 5;

对于具有该配置文件的用户,如果他们的密码至少已经改变了5次,则这些密码可以在20天后重新使用。如果为其中一个参数指定一个值,而为另一个参数指定UNLIMITED,则用户可以永远不重用密码。

和大多数其他的操作一样,可以使用Oracle Enterprise Manager可以很容易地管理配置文件。图109-4显示了一个示例:将DEFAULT配置文件改为在15分钟不活动后取消用户连接。

image054.jpg

图109-4  使用Oracle Enterprise Manager改变密码限制

如果希望对如何创建和重用密码提供更紧密严格的 控制,例如在每个密码中混合使用大写字母和小写字母,则需要在每个应用程序配置文件中启用PASSWORD_VERIFY_FUNCTION限制。 Oracle提供了一个模板来实施组织的密码策略。该模板位于$ORACLE_HOME/rdbms/admin/ utlpwdmg.sql。附录A中给出了该脚本的一些关键部分如下:

CREATE OR REPLACE FUNCTION verify_function_11G

(username varchar2,

  password varchar2,

  old_password varchar2)

  RETURN boolean IS

   n boolean;

   m integer;

   differ integer;

   isdigit boolean;

   ischar  boolean;

   ispunct boolean;

   db_name varchar2(40);

   digitarray varchar2(20);

   punctarray varchar2(25);

   chararray varchar2(52);

   i_char varchar2(10);

   simple_password varchar2(10);

   reverse_user varchar2(32);

BEGIN

   digitarray:= '0123456789';

   chararray:= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

. . .

   -- Check if the password is same as the username reversed

   FOR i in REVERSE 1..length(username) LOOP

     reverse_user := reverse_user || substr(username, i, 1);

   END LOOP;

   IF NLS_LOWER(password) = NLS_LOWER(reverse_user) THEN

     raise_application_error(-20003, 'Password same as username reversed');

   END IF;

. . .

   -- Everything is fine; return TRUE ;

   RETURN(TRUE);

END;

/

-- This script. alters the default parameters for Password Management

-- This means that all the users on the system have Password Management

-- enabled and set to the following values unless another profile is

-- created with parameter values set to different value or UNLIMITED

-- is created and assigned to the user.

ALTER PROFILE DEFAULT LIMIT

PASSWORD_LIFE_TIME 180

PASSWORD_GRACE_TIME 7

PASSWORD_REUSE_TIME UNLIMITED

PASSWORD_REUSE_MAX UNLIMITED

FAILED_LOGIN_ATTEMPTS 10

PASSWORD_LOCK_TIME 1 PASSWORD_VERIFY_FUNCTION verify_function_11G;

一个缩写版本。

该脚本为密码复杂性提供了如下功能函数:

●       确保密码与用户名不同。

●       确保密码至少具有4个字符长。

●       进行检查,确保密码不是简单的、显而易见的单词,例如ORACLE或DATABASE。

●       需要密码包含一个字母、一个数字以及一个标点符号。

●       确保密码与前面的密码至少有3个字符不同。

为了使用这一策略,首先应对该脚本进行自定义改动。例如,可能希望具有几个一些不同的验证函数,每一个函数种功能针对一个国家或一个业务部门企业单位,用于将数据库密码复杂性需求匹配特定国家或企业单位业务部门中使用的操作系统的需求。例如,可以将这种函数重命名为VERIFY_FUNCTION_ US_MIDWEST。此外,可能希望将简单单词的列表改为包括公司的中部门名称或建筑大楼的名称。

一旦成功编译该函数,可以通过alter profile命令,改变已有的配置文件以使用该函数,或者可以创建使用该函数的新的配置文件。在下面的示例中,改变DEFAULT配置文件以使用函数VERIFY_FUNCTION_US_MIDWEST:

SQL> alter profile default limit

  2      password_verify_function verify_function_us_midwest;

Profile altered.

SQL> alter profile default limit

password_verify_function verify_function_us_midwest;

对于所有使用DEFAULT配置文件的已有用户,或 者是使用DEFAULT配置文件的新用户,通过VERIFY_FUNCTION_US_MIDWEST函数检查他们的密码。如果该函数返回不同于TRUE 的值,则不允许该密码,用户必须指定不同的密码。如果用户的当前密码不符合该函数中的规则,该密码仍然有效,直到改变密码,此时该函数必须验证新的密码。

3. 配置文件和资源控制

表109-5中列出了使用CREATE PROFILE profilename LIMIT后可以出现的资源控制配置文件选项列表。每个参数都可以是整数、UNLIMITED或DEFAULT。

表109-5  与资源相关的配置文件参数

资 源 参 数

说    明

SESSIONS_PER_USER

用户可以同时具有的最大会话数量

CPU_PER_SESSION

每个会话允许的最大CPU时间,以1%秒为单位

CPU_PER_CALL

语句解析、执行或读取操作的最大CPU时间,以1%秒为单位

CONNECT_TIME

最大总计消耗时间,以分钟为单位

IDLE_TIME

当查询或其他操作停止执行时,会话中的最大连续不活动时间,以分钟为单位,同时查询或其他操作没有在进行中

LOGICAL_READS_PER_SESSION

每个会话从内存或磁盘中读取的数据块总量

LOGICAL_READS_PER_CALL

语句解析、执行或读取操作的最大数据块读取量

COMPOSITE_LIMIT

以服务单位划分的总计资源成本,作为CPU_PER_SESSION、CONNECT_TIME、LOGICAL_READS_PER_SESSION和PRIVATE_SGA的组合加权和

PRIVATE_SGA

会话可以在共享池中分配的最大内存量,以字节、千字节或兆字节为单位

 

 

和密码相关的参数一样,UNLIMITED表示没有限制可以使用的资源数量。DEFAULT表示该参数从DEFAULT配置文件中获得它的值。

COMPOSITE_LIMIT参数允许在使用的资源类型剧烈变化时控制一组资源限制。它允许用户在一个会话期间使用大量CPU时间和较少的磁盘I/O,而在另一个会话期间采用相反的情况,但不需要通过策略来保持取消连接。

默认情况下,所有的资源成本为0:

SQL> select * from resource_cost;

RESOURCE_NAME                         UNIT_COST

-------------------------------- ----------

CPU_PER_SESSION                             0

LOGICAL_READS_PER_SESSION                0

CONNECT_TIME                              0

PRIVATE_SGA                                 0

4 rows selected.

SQL> select * from resource_cost;

 

RESOURCE_NAME                    UNIT_COST

-------------------------------- ----------

CPU_PER_SESSION                         0

LOGICAL_READS_PER_SESSION                0

CONNECT_TIME                            0

PRIVATE_SGA                             0

 

为了调整资源成本的权值,可以使用ALTER RESOURCE COST命令。在下面的示例中,改变加权,从而CPU_PER_SESSION更关注CPU利用率而不是连接时间,其比例系数为25:1。换句话说,用户 将更可能由于CPU利用率(而不是连接时间)而取消连接:

SQL> alter resource cost

  2      cpu_per_session 50

  3      connect_time 2;

Resource cost altered.

SQL> select * from resource_cost;

RESOURCE_NAME                     UNIT_COST

-------------------------------- ----------

CPU_PER_SESSION                          50

LOGICAL_READS_PER_SESSION                 0

CONNECT_TIME                              2

PRIVATE_SGA                               0

4 rows selected.

SQL> alter resource cost

cpu_per_session 50

connect_time 2;

Resource cost altered.

 

SQL> select * from resource_cost;

 

RESOURCE_NAME                      UNIT_COST

-------------------------------- ----------

CPU_PER_SESSION                           50

LOGICAL_READS_PER_SESSION                  0

CONNECT_TIME                               2

PRIVATE_SGA                                0

 

下一步是创建新的配置文件或修改已有的配置文件,从而可以使用组合的限制:

SQL> create profile lim_comp_cpu_conn limit

  2      composite_limit 250;

Profile created.

SQL> create profile lim_comp_cpu_conn limit

composite_limit 250;

 

作为因此,赋予配置文件LIM_COMP_CPU_CONN的用户将使用下面的公式计算成本,从而限制他们的会话资源:

composite_cost = (50 * CPU_PER_SESSION) + (2 * CONNECT_TIME);

在表109-6中,提供了一些资源利用的一些示例,用于查看是否超出了组合限制250。

表109-6  资源利用情况

CPU(秒)

连接(秒)

组合的成本

是 否 超 出

0.05

100

(50*5) + (2*100) = 450

0.02

30

(50*2) + (2*30) = 160

0.01

150

(50*1) + (2*150) = 350

0.02

5

(50*2) + (2*5) = 110

在这个特定 的示例中没有使用参数PRIVATE_SGA和LOGICAL_READS_PER_SESSION,除非在配置文件定义中的其他位置指定它们,否则它们 默认为在DEFAULT配置文件中的值。使用组合限制的目的在于用户可以运行更多类型的查询或DML。在某些天中,他们可能运行许多查询,这些查询执行大 量计算,但是没有访问过多的表行。在其他一些天中,他们可能执行许多完整的表扫描,但是没有保持长时间的连接。在这些情况中,不希望通过单一的一个参数来限制用户,而是通过总计的资源利用率来限制用户,该资源利用率按照服务器上每个资源的可用性的加权来获得该利用率。

109.3.2  系统权限

系统权限是在数据库中任何对象上执行操作的权利,以及其他一些权限,这些权限完全不涉及对象,而是涉及运行批处理工作作业、改变系统参数、创建角色、甚至是连接到数据库自身等方面。Oracle 10g11g的版本1中有173206个系统权限。可以在数据字典表SYSTEM_PRIVILEGE_MAP中看到所有这些权限:

SQL> select * from system_privilege_map;

PRIVILEGE   NAME                                           PROPERTY

---------- -------------------------------------    ----------

        -3   ALTER SYSTEM                                     0

        -4   AUDIT SYSTEM                                     0

        -5   CREATE SESSION                                   0

        -6   ALTER SESSION                                    0

        -7   RESTRICTED SESSION                              0

       -10    CREATE TABLESPACE                               0

       -11    ALTER TABLESPACE                                  0

       -12    MANAGE TABLESPACE                               0

       -13    DROP TABLESPACE                                  0

       -15    UNLIMITED TABLESPACE                            0

       -20    CREATE USER                                       0

       -21    BECOME USER                                       0

       -22    ALTER USER                                        0

       -23    DROP USER                                         0

. . .

      -318   INSERT ANY MEASURE FOLDER                       0

      -319   CREATE CUBE BUILD PROCESS                      0

      -320   CREATE ANY CUBE BUILD PROCESS                 0

      -321   DROP ANY CUBE BUILD PROCESS                   0

      -322   UPDATE ANY CUBE BUILD PROCESS                  0

      -326   UPDATE ANY CUBE DIMENSION                      0

      -327   ADMINISTER SQL MANAGEMENT OBJECT             0

      -350   FLASHBACK ARCHIVE ADMINISTER                  0

206 rows selected.

SQL> select * from system_privilege_map;

 

PRIVILEGE   NAME                                    PROPERTY

---------- --------------------------------------- ----------

-3   ALTER SYSTEM                                  0

-4   AUDIT SYSTEM                                  0

-5   CREATE SESSION                                 0

-6   ALTER SESSION                                  0

-7   RESTRICTED SESSION                             0

-10 CREATE TABLESPACE                              0

-11 ALTER TABLESPACE                              0

-12 MANAGE TABLESPACE                              0

-13 DROP TABLESPACE                                0

-15 UNLIMITED TABLESPACE                           0

-20 CREATE USER                                  0

-21 BECOME USER                                   0

-22 ALTER USER                                    0

-23 DROP USER                                     0

-271 ALTER ANY SQL PROFILE                          0

-272 ADMINISTER SQL TUNING SET                      0

-273 ADMINISTER ANY SQL TUNING SET                   0

-274 CREATE ANY SQL PROFILE                         0

-275 EXEMPT IDENTITY POLICY                         0

表109-7列出了一些更为常见的系统权限,并且简要描述了这些权限。

表109-7 常见的系统权限

系 统 权 限

功    能

ALTER DATABASE

对数据库进行改动,例如将数据库状态从MOUNT改为OPEN,或者是恢复数据库

ALTER SYSTEM

发布ALTER SYSTEM语句:切换到下一个重做日志组,改变或者在SPFILE中的改变系统初始参数

AUDIT SYSTEM

发布AUDIT语句

CREATE DATABASE LINK

创建到远程数据库的数据库链接

CREATE ANY INDEX

在任意模式中创建索引;针对用户的模式,连同随同CREATE TABLE一起授权CREATE INDEX

                                                                 (续表)  

系 统 权 限

功    能

CREATE PROFILE

创建资源/密码配置文件

CREATE PROCEDURE

在自己的模式中创建函数、过程或程序包

CREATE ANY PROCEDURE

在任意的模式中创建函数、过程或程序包

CREATE SESSION

连接到数据库

CREATE SYNONYM

在自己的模式中创建私有同义词

CREATE ANY SYNONYM

在任意模式中创建私有同义词

CREATE PUBLIC SYNONYM

创建公有同义词

DROP ANY SYNONYM

在任意模式中删除私有同义词

DROP PUBLIC SYNONYM

删除公有同义词

CREATE TABLE

在自己的模式中创建表

CREATE ANY TABLE

在任意模式中创建表

CREATE TABLESPACE

在数据库中创建新的表空间

CREATE USER

创建用户账户/模式

ALTER USER

改动用户账户/模式

CREATE VIEW

在自己的模式中创建视图

SYSDBA

如果启用了外部密码文件,则在外部密码文件中创建一个条目,如果启用外部密码文件的话;同时,执行启动/关闭数据库,改变数据库,创建数据库,恢复数据库,创建SPFILE,以及当数据库处于RESTRICTED SESSION模式时连接数据库

SYSOPER

如果启用了外部密码文件,则在外部密码文件中创建一个条目,如果启用外部密码文件的话;同时,执行启动/关闭数据库,改变数据库,创建数据库,恢复数据库,创建SPFILE,以及当数据库处于RESTRICTED SESSION模式时连接数据库

1. 授予系统权限

使用grant命令将权限授予用户、角色或PUBLIC,使用revoke命令取消权限。PUBLIC是一个特殊的组,包含所有的数据库用户,通过它可以方便快捷地将权限授予数据库中的每  个人。

为了授予用户SCOTT创建存储过程和同义词的能力,可以使用类似于如下的命令:

SQL> grant create procedure, create synonym to scott;

Grant succeeded.

取消权限也非常容易:

SQL> revoke create synonym from scott;

Revoke succeeded.

如果希望允许被授权者有权将相同的权限授予其他某个人,可以在授予权限时包括with admin option选项。在前面的示例中,希望用户SCOTT能够将CREATE PROCEDURE权限授予其他用户。为了实现这一点,需要重新授予CREATE PROCEDURE权限:

SQL> grant create procedure to scott with admin option;

Grant succeeded.

现在用户SCOTTScott可以发布grant create procedure命令。注意,如果取消SCOTT将Scott授予该权限授予其他人的许可,他已经授予权限的用户将保留该权限。

2. 系统权限数据字典视图

表109-8包含了与系统权限相关的数据字典视图。

表109-8  系统权限数据字典视图

数据字典视图

说    明

DBA_SYS_PRIVS

赋予角色和用户的系统权限

SESSION_PRIVS

对该会话的这个用户有效的所有系统权限,直接授权或通过角色

ROLE_SYS_PRIVS

通过角色授权给用户的当前会话权限

109.3.3  对象权限

与系统权限相比,对象权限是在特定对象(如表或序列)上执行特定类型操作的权利,该对象不在用户自己的模式中。和系统权限一样,使用grant和revoke命令来授予或和取消对象上的   权限。

和系统权限一样,可以授予对象权限给PUBLIC或特定用户,并且具有对象权限的用户可以将其传递给其他用户,其方法是使用with grant option子句授予对象权限。

警告:

当所有当前的和未来的数据库用户确切地需要权限时,只将对象权限或系统权限授予PUBLIC。

一些模式对象,例如集群和索引,依赖于系统权限来控制访问。在这些情况中,如果用户拥有这些对象或具有ALTER ANY CLUSTER或ALTER ANY INDEX系统权限,则可以改变这些对象。

在自己的模式中拥有对象的用户自动具有这些对象上的所有对象权限,并且可以将这些对象上的任何对象权限授予任意用户或另一个角色,使用或不使用grant option子句。

表109-9中是可用于不同类型对象的对象权限,一些权限只适用于某些类型的对象。例如,INSERT权限只对表、视图和物化视图有意义。另一方面,EXECUTE权限适用于函数、过程和程序包,但不适用于表。

表109-9  对象权限

对 象 权 限

功    能

ALTER

可以改变表或序列的定义

DELETE

可以从表、视图或物化视图中删除行

EXECUTE

可以执行函数或过程,使用或不使用程序包

DEBUG

允许查看在表上定义的触发器中的PL/SQL代码,或者查看引用表的SQL语句。对于对象类型,该权限允许访问在对象类型上定义的所有共有和私有变量、方法和类型

FLASHBACK

允许使用保留的撤销信息在表、视图和物化视图中进行闪回查询

INDEX

可以在表上创建索引

INSERT

可以在向表、视图或物化视图中插入行

ON COMMIT REFRESH

可以根据表创建提交后刷新的物化视图

QUERY REWRITE

可以根据表创建用于查询重写的物化视图

READ

可以使用Oracle DIRECTORY定义读取操作系统目录的内容

REFERENCES

可以创建引用另一个表的主键或唯一键的外键约束

SELECT

可以从表、视图或物化视图中读取行,此外还可以从序列中读取当前值或下面的值

UNDER

可以根据已有的视图创建视图

UPDATE

可以更新表、视图或物化视图中的行

WRITE

可以使用Oracle DIRECTORY定义将信息写入到操作系统目录

值得注意的是,不可以将DELETE、UPDATE和INSERT权限授予物化视图,除非这些视图是可更新的。一些对象权限和系统权限重复;例如,如果没有表上的FLASHBACK对象权限,但只要有FLASHBACK ANY TABLE系统权限,就仍然可以执行闪回查询。

在下面的示例中,DBA授权SCOTT对表HR.EMPLOYEES的完全访问,但只允许SCOTT将SELECT对象权限授权传递给其他用户:

SQL> grant insert, update, delete on hr.employees to scott;

Grant succeeded.

SQL> grant select on hr.employees to scott with grant option;

Grant succeeded.

SQL> grant insert, update, delete on hr.employees to scott;

Grant succeeded.

SQL> grant select on hr.employees to scott with grant option;

注意,如果取消了SCOTT在表HR.EMPLOYEES上的SELECT权限,则也取消他授予该权限的用户的SELECT权限。

1. 表权限

可以在表上授予的权限类型主要分为两类:DML操作和DDL操作。DML操作包括delete、insert、select和update,而DDL操作包括添加、删除和改变表中的列,以及在表上创建索引。

授权表上的DML操作时,可以将这些操作限制为只针对某些列。例如,可能希望允许SCOTT查看和更新HR.EMPLOYEES中所有的行和列,除了SALARY列。为了做到这一点,首先需要取消表上已有的SELECT权限:

SQL> revoke update on hr.employees from scott;

Revoke succeeded.

接下来,让SCOTT更新除了SALARY列之外的所有列:

SQL> grant update (employee_id, first_name, last_name, email,

  2               phone_number, hire_date, job_id, commission_pct,

  3               manager_id, department_id)

  4  on hr.employees to scott;

Grant succeeded.

SQL> grant update (employee_id, first_name, last_name, email,

phone_number, hire_date, job_id, commission_pct,

manager_id, department_id)

on hr.employees to scott;

SCOTT将能够更新HR.EMPLOYEES表中除了SALARY列之外的所有列:

SQL> update hr.employees set first_name = 'Stephen' where employee_id = 100;

1 row updated.

SQL> update hr.employees set salary = 50000 where employee_id = 203;

update hr.employees set salary = 50000 where employee_id = 203

          *

ERROR at line 1:

ORA-01031: insufficient privileges

SQL> update hr.employees set first_name = ‘Stephen’ where employee_id = 100;

1 row updated.

SQL> update hr.employees set salary = 50000 where employee_id = 203;

update hr.employees set salary = 50000 where employee_id = 203

*

ERROR at line 1:

也可以使用基于Web的OEM工具也很容易地执行该操作,如图109-5所示。

image055.jpg

图109-5  在Oracle Enterprise Manager中授予列权限

2. 视图权限

视图上的权限类似于在表上授予的权限。假设视图是可更新的,则可以选择、更新、删除或插入视图中的行,假设视图是可更新的。为了创建视图,首先需要CREATE VIEW系统权限(用于在自己的模式中创建视图)或CREATE ANY VIEW系统权限(用于在任意模式中创建视图)。即使是创建视图,也必须至少具有视图的底层表上的SELECT对象权限,以及INSERT、UPDATE和DELETE等对象权限(,如果希望在视图上执行这些操作,并且视图是可更新的)。作为选择,如果底层的对象不在自己的模式中,则可以有SELECT ANY TABLE、INSERT ANY TABLE、UPDATE ANY TABLE或DELETE ANY TABLE权限。

为了允许其他人使用您的视图,必须使用GRANT OPTION具有视图的基表上的许可,或者必须使用ADMIN OPTION具有系统权限。例如,如果创建针对HR.EMPLOYEES表的视图,则必须通过WITH GRANT OPTION子句授予HR.EMPLOYEES表上的SELECT系统对象权限,或者通过WITH ADMIN OPTION子句具有SELECT ANY TABLE系统权限。

3. 过程权限

对于过程、函数以及包含过程和函数的程序包,EXECUTE权限是唯一可以应用的对象权限。从Oracle 8i开始,可以从定义者、过程或函数的创建者、调用者、运行函数或过程的用户等的角度来运行过程和函数。

使用定义者的权利运行过程时,如同定义者自身运行该过程一样,定义者所有的权限都对过程中引用的对象有效。这是在私有数据库对象上实施约束的好方法:授予其他用户在过程上的EXECUTE许可,而没有授予引用对象上的任何许可。结果,定义者可以控制其他用户如何访问对象。

相反,使用调用者权利的过程需要调用者具有针对该过程中引用的任何对象的直接权利,例如SELECT和UPDATE。该过程可能引用了无限制限定的表ORDERS,并且如果数据库的所有用户都具有ORDERS表,则具有自己有的ORDERS表的任何用户都可以使用相同的过程。使用调用者权利的过程的另一个优点是在过程它们中启用该角色。本章后面将深入讨论角色。

默认情况下,使用定义者的权利创建过程。为了指定过程使用调用者的权利,必须在过程定义中包括关键字authid current_user,如同下面的示例所示:

create or replace procedure process_orders (order_batch_date   date)

authid current_user as

begin

     -- process user's ORDERS table here using invoker's rights,

     -- all roles are in effect

end;

create or replace procedure process_orders (order_batch_date date)

authid current_user as

begin

process user’s ORDERS table here using invoker’s rights,

all roles are in effect

为了创建过 程,用户必须具有CREATE PROCEDURE或CREATE ANY PROCEDURE系统权限。对于正确编译的过程,用户必须具有针对过程中引用的所有对象的直接权限,即使在运行时,在使用调用者权利的过程中启用了角色 以获得这些相同的权限。为了允许其他用户访问过程,可以授予过程或程序包上的EXECUTE权限。

4. 对象权限数据字典视图

大量数据字典视图包含了赋予用户的对象权限的相关信息。表109-10列出了包含对象权限信息的最重要的视图。

表109-10  对象权限数据字典视图

数据字典视图

说    明

DBA_TAB_PRIVS

授予角色和用户的表权限。包括将权限授予角色或用户的用户,使用或不使用GRANT OPTION

DBA_COL_PRIVS

授予角色或用户的列权限。包含列名和列上的权限类型

SESSION_PRIVS

对会话的该用户有效的所有系统权限,直接授予或通过角色

ROLE_TAB_PRIVS

对于当前的会话,通过角色授予的表上的权限

109.3.4  创建、分配和维护角色

角色是一组指定的权限,这些权限是系统权限、对象权限或者两者的结合,用于帮助简化权限的管理。不同于单独将系统权限或对象权限授予每个用户,可以将一组系统权限或对象权限授予一个角色,然后将该角色授予用户。这将大量减少维护用户的权限所需的管理系统开销。图109-6显示了角色如何减少在将角色用于分组权限时需要执行的grant命令(最终是revoke命令)的数量。

图109-6  使用角色管理权限

如果需要改变由角色授权给一组人的权限,则只需要改变该角色的权限,并且具有该角色的用户有能力的功能将自动使用改动后的新权限。用户可以由用户有选择地启用角色,一些有些角色可以能在登录注册时就自动启用。此外,可以使用密码保护角色,添加对数据库中该功能的另一种验证级别。

在表109-11中是和数据库一起自动提供的最常见的角色,其中也简要描述了每个角色中的  权限。

表109-11  预定义的Oracle角色

角  色  名

权    限

CONNECT

Oracle Database 10g版本2之前的版本:ALTER SESSION、CREATE CLUSTER、CREATE DATABASE LINK、CREATE SEQUENCE、CREATE SESSION、CREATE SYNONYM、CREATE TABLE、CREATE VIEW。这些权限一般是提供给数据库中普通用户的权限,允许他们连接和创建表、索引以及视图。Oracle Database 10g版本2及之后的版本:只有CREATE SESSION

                                                                         (续表)   

角  色  名

权    限

RESOURCE

CREATE CLUSTER、CREATE INDEXTYPE、CREATE OPERATOR、CREATE PROCEDURE、CREATE SEQUENCE、CREATE TABLE、CREATE TRIGGER、CREATE TYPE。这些权限一般用于可能正在编写码PL/SQL过程和函数的应用程序开发人员

DBA

所有具有WITH ADMIN OPTION的系统权限。允许具有DBA角色的人将系统权限授予其他人

DELETE_CATALOG_ROLE

没有任何系统权限,而只有SYS.AUD$和FGA_LOG$上的对象权限(DELETE)。换句话说,该角色允许用户从用于常规或细粒度审计的审计跟踪中删除审计记录

EXECUTE_CATALOG_ROLE

各种系统程序包、过程和函数上的执行权限,例如DBMS_FGA和DBMS_RLS

SELECT_CATALOG_ROLE

1 638个数据字典表上的SELECT对象权限

EXP_FULL_DATABASE

EXECUTE_CATALOG_ROLE、SELECT_CATALOG_ROLE、以及诸如BACKUP ANY TABLE和RESUMABLE等系统权限。允许具有该角色的用户导出数据库中的所有对象

IMP_FULL_DATABASE

类似于EXP_FULL_DATABASE,但是具有许多更多多很多的系统权限,例如CREATE ANY TABLE,用于允许导入前面导出的完整数据库

AQ_USER_ROLE

Advanced Queuing所需例程的执行访问,例如DBMS_AQ

AQ_ADMINISTRATOR_ROLE_ROLE

Advanced Queuing查询的管理程序

SNMPAGENT

由Enterprise Manager Intelligent Agent使用

RECOVERY_CATALOG_OWNER

用户用于创建一个用户,该用户拥有用于RMAN备份和恢复的恢复目录

HS_ADMIN_ROLE

提供对表HS_*和程序包DBMS_HRHS的访问,用于管理Oracle Heterogeneous Services

SCHEDULER_ADMIN

提供对程序包DBMS_SCHEDULER的访问,以及用于创建批处理工作作业的权限

提供角色CONNECT、RESOURCE和DBA主要是为了兼容以前的Oracle版本,而在将来的Oracle版本中可能不会有这些角色。数据库管理员应该使用授权给这些角色的权限作为起点来创建自定义的角色。

1. 创建或删除角色

为了创建角色,可以使用create role命令,并且必须具有CREATE ROLE系统权限。一般来说,该系统权限只授权给数据库管理员或应用程序管理员。下面是示例:

SQL> create role hr_admin not identified;

Role created.

SQL> create role hr_admin not identified;

默认情况下,启用或使用已分配的角色不需要任何密码或验证。因此,not identified子句是可    选项。

和创建用户一样,可以通过密码(使用identified by password的数据库授权)、通过操作系统(identified externally)、或者通过网络或目录服务(identified globally)授权使用角色。

除了这些熟悉的方法,还可以通过使用程序包授权角色:这称为使用“安全应用程序角色”。这种类型的角色使用程序包中的过程来启用角色。一般来说,只在某些条件下启用这种角色:用户正在通过Web接口或某个IP地址连接,或者是一天的某个时间。下面是使用过程启用的角色:

SQL> create role hr_clerk identified using hr.clerk_verif;

Role created.

SQL> create role hr_clerk identified using hr.clerk_verif;

创建角色时,过程HR.CLERK_VERIF不需 要存在。然而,当授予该角色的用户需要启用它时,它必须经过编译并且有效。一般来说,使用安全应用程序角色时,默认情况下不针对用户启用该角色。为了指定 在默认情况下启用除了安全应用程序角色之外的所有角色,可以使用如下的命令:

SQL> alter user kshelton default role all except hr_clerk;

User altered.

SQL> alter user wgietz default role all except hr_clerk;

通过这种方式,当HR应用程序启动时,它可以启用角色,其方法是执行set role hr_clerk命令,从而调用过程HR.CLERK_VERIF。用户不需要知道角色或启用角色的过程,因此,对象的访问和角色提供的权限都不可用于应用程序外部的用户。

删除角色和创建角色一样简单:

SQL> drop role keypunch_operator;

Role dropped.

SQL> drop role keypunch_operator;

下一次连接到数据库时,赋予该角色的任何用户将丢失赋予该角色的权限。如果他们当前已经注册登录,他们将保留这些权限,直到断开与取消数据库的连接。

2. 将权限授予角色

将权限赋予角色非常简单,可以使用grant命令将权限赋予角色,如同将权限赋予用户一样:

SQL> grant select on hr.employees to hr_clerk;

Grant succeeded.

SQL> grant create table to hr_clerk;

Grant succeeded.

SQL> grant select on hr.employees to hr_clerk;

Grant succeeded.

SQL> grant create trigger to hr_clerk;

在该示例中,将对象权限和系统权限赋予HR_CLERK角色。在图109-7中,可以使用基于Web的OEM来将更多的对象权限或系统权限添加给该角色。

image057.jpg

图109-7  使用OEM将权限赋予角色

3. 分配或取消角色

一旦已经将所需的对象权限和系统权限赋予角色,就可以使用如下熟悉的语法将角色赋予 用户:

SQL> grant hr_clerk to smavris;

Grant succeeded.

SQL> grant hr_clerk to smavris;

SMAVRIS可以自动使用未来授予任何授权给HR_CLERK角色的其他任何权限在将来可以通过SMAVRIS使用,因为SMAVRIS已经被授予该角色。

角色可以授予其他角色,这就允许DBA设计多层次的 角色,从而使角色管理更为容易。例如,可能已经具有名为DEPT30、DEPT50和DEPT100的角色,每个角色具有一些对象权限,分别对应各个部门 的表。部门30中的雇员将分配DEPT30角色,依此类推。公司的董事长希望看到所有部门中的表,不必将单个的对象权限赋予角色ALL_DEPTS,而是 可以将单个的部门角色赋予ALL_DEPTS:

SQL> create role all_depts;

Role created.

SQL> grant dept30, dept50, dept100 to all_depts;

Grant succeeded.

SQL> grant all_depts to sking;

Grant succeeded.

SQL> create role all_depts;

Role created.

SQL> grant dept30, dept50, dept100 to all_depts;

Grant succeeded.

SQL> grant all_depts to sking;

角色ALL_DEPTS可能也包含单个对象权限和系统权限,这些权限不适用于单个部门,例如订单条目表或账户应收款项表上的对象权限。

从用户处取消角色非常类似于从用户处取消权限:

SQL> revoke all_depts from sking;

Revoke succeeded.

SQL> revoke all_depts from sking;

下次用户连接到数据库时,这些取消的权限将不再可用于这些用户。然而,值得注意的是,如果另一个角色包含与删除角色相同对象上的权限,或者直接授予对象上的权限,则用户将保留对象上的这些权限,直到显式地取消这些授权和所有其他授权。

4. 默认的角色

默认情况下,当用户连接到数据库时启用授予该用户的所有角色。如果角色将只用于应用程序的上下文中,则在用户注册登录时可以先禁用该角色,然后在应用程序中启用和禁用该角色。如果用户SCOTT具有CONNECT、RESOURCE、HR_CLERK和DEPT30角色,希望指定HR_CLERK和DEPT30默认情况下不启用,则可以使用类似于如下的代码:

SQL> alter user scott default role all

  2>     except hr_clerk, dept30;

User altered.

SQL> alter user scott default role all

2>     except hr_clerk, dept30;

当SCOTT连接到数据库时,他自动具有通过除了除HR_CLERK和DEPT30之外的所有角色授予的所有权限。通过使用set role,SCOTT可以在他的会话中显式地启用一个角色:

SQL> set role dept30;

Role set.

当完成对部门30的表的访问时,可以在会话中禁用该角色:

SQL> set role all except dept30;

Role set.

注意:

在Oracle 10g中不赞成使用初始参数MAX_ENABLED_ROLES。保留该参数只是为了和以前的版本兼容。

5. 启用密码的角色

为了增强数据库中的安全性,DBA可以为角色赋予密码。在创建角色时为其赋予密码:

SQL> create role dept99 identified by d99secretpw;

Role created.

SQL> grant dept99 to scott;

Grant succeeded.

SQL> alter user scott default role all except hr_clerk, dept30, dept99;

User altered.

SQL> create role dept99 identified by d99secretpw;

Role created.

SQL> grant dept99 to scott;

Grant succeeded.

SQL> alter user scott default role all except hr_clerk, dept30, dept99;

当用户SCOTT连接到数据库时,他正在使用的应用程序将提供密码或提示用户输入密码,或者他可以在启用角色时输入密码:

SQL> set role dept99 identified by d99secretpw;

Role set.

6. 角色数据字典视图

表109-12列出了与角色相关的数据字典视图。

表109-12  与角色相关的数据字典视图

数据字典视图

说    明

DBA_ROLES

所有的角色以及它们是否需要密码

DBA_ROLE_PRIVS

授予用户或其他角色的角色

ROLE_ROLE_PRIVS

授予其他角色的角色

ROLE_SYS_PRIVS

已经授予角色的系统权限

ROLE_TAB_PRIVS

已经授予角色的表权限和表列权限

SESSION_ROLES

当前对该会话有效的角色。可用于每个用户会话

视图DBA_ROLE_PRIVS可以很好地用于:找出哪些角色被授予了用户,这些用户是否可以将该角色传递给另一个用户(ADMIN_OPTIONADMIN OPTION),以及该角色是否在默认情况下启用(DEFAULT_ROLE):

SQL> select * from dba_role_privs

  2        where grantee = 'SCOTT';

GRANTEE      GRANTED_ROLE         ADMIN_OPTION DEFAULT_ROLE

----------- -------------------- ------------ ------------

SCOTT        DEPT30                  NO              NO

SCOTT        DEPT50                  NO              YES

SCOTT        DEPT99                  NO              YES

SCOTT        CONNECT                 NO              YES

SCOTT        HR_CLERK                NO              NO

SCOTT        RESOURCE                NO              YES

SCOTT        ALL_DEPTS               NO              YES

SCOTT        DELETE_CATALOG_ROLE  NO              YES

8 rows selected.

SQL> select * from dba_role_privs

2        where grantee = 'SCOTT';

 

GRANTEE     GRANTED_ROLE        ADMIN_OPTION DEFAULT_ROLE

------------ -------------------- ------------ ------------

SCOTT       DEPT30              NO           NO

SCOTT       DEPT50              NO           YES

SCOTT       DEPT99              NO           YES

SCOTT       CONNECT              NO           YES

SCOTT       HR_CLERK            NO           NO

SCOTT       RESOURCE            NO           YES

SCOTT       ALL_DEPTS           NO           YES

SCOTT       DELETE_CATALOG_ROLE NO           YES

类似地,可以找出将哪些角色赋予ALL_DEPTS角色:

SQL> select * from dba_role_privs

  2>       where grantee = 'ALL_DEPTS';

GRANTEE        GRANTED_ROLE        ADMIN_OPTION DEFAULT_ROLE

------------ ------------------ ------------ ------------

ALL_DEPTS      DEPT30               NO              YES

ALL_DEPTS      DEPT50               NO              YES

ALL_DEPTS      DEPT100              NO              YES

3 rows selected.

SQL> select * from dba_role_privs

2> where grantee = 'ALL_DEPTS';

GRANTEE      GRANTED_ROLE        ADMIN_OPTION DEFAULT_ROLE

------------ -------------------- ------------ ------------

ALL_DEPTS    DEPT30              NO          YES

ALL_DEPTS    DEPT50              NO          YES

ALL_DEPTS    DEPT100             NO          YES

 

数据字典视图ROLE_ROLE_PRIVS也可以用于获得这些信息。它只包含有关赋予角色的角色信息,没有DEFAULT_ROLE信息。

 

 

为了找出表或表列上授予用户的权限,可以编写2个查询:一个查询用于检索直接授予的权限,另一个查询用于检索通过角色间接授予的权限。检索直接授予的权限非常简单:

SQL> select dtp.grantee, dtp.owner, dtp.table_name,

  2        dtp.grantor, dtp.privilege, dtp.grantable

  3  from dba_tab_privs dtp

  4  where dtp.grantee = 'SCOTT';

GRANTEE      OWNER      TABLE_NAME     GRANTOR     PRIVILEGE  GRANTABLE

----------- --------- ------------- ---------- ---------- ----------

SCOTT        HR         EMPLOYEES      HR            SELECT       YES

SCOTT        HR         EMPLOYEES      HR           DELETE       NO

SCOTT        HR         EMPLOYEES      HR           INSERT       NO

4 rows selected.

SQL> select dtp.grantee, dtp.owner, dtp.table_name,

2        dtp.grantor, dtp.privilege, dtp.grantable

3   from dba_tab_privs dtp

4   where dtp.grantee = 'SCOTT';

GRANTEE     OWNER     TABLE_NAME      GRANTOR      PRIVILEGE    GRANTABLE

------------ ---------- --------------- ------------ ------------ ----------

SCOTT       HR         EMPLOYEES       HR           SELECT       YES

SCOTT       HR         EMPLOYEES       HR           DELETE       NO

SCOTT       HR         EMPLOYEES       HR           INSERT       NO

为了检索通过角色授予的表权限,需要连接DBA_ROLE_PRIVS和ROLE_TAB_PRIVS。DBA_ROLE_PRIVS具有赋予用户的角色,而ROLE_TAB_PRIVS具有赋予角色的权限:

SQL> select drp.grantee, rtp.owner, rtp.table_name,

  2       rtp.privilege, rtp.grantable, rtp.role

  3  from role_tab_privs rtp

  4       join dba_role_privs drp on rtp.role = drp.granted_role

  5  where drp.grantee = 'SCOTT';

GRANTEE   OWNER    TABLE_NAME      PRIVILEGE    GRANTABLE  ROLE

--------- ------- -------------- ------------ ---------- ---------------

SCOTT      HR       EMPLOYEES       SELECT       NO         HR_CLERK

SCOTT      HR       JOBS              SELECT       NO         JOB_MAINT

SCOTT      HR       JOBS              UPDATE       NO         JOB_MAINT

SCOTT      SYS      AUD$              DELETE       NO         DELETE_CATA

                                                                   LOG_ROLE

SCOTT      SYS      FGA_LOG$        DELETE       NO         DELETE_CATA

                                                                   LOG_ROLE

5 rows selected.

SQL> select drp.grantee, rtp.owner, rtp.table_name,

2       rtp.privilege, rtp.grantable, rtp.role

3   from role_tab_privs rtp

4       join dba_role_privs drp on rtp.role = drp.granted_role

5   where drp.grantee = 'SCOTT';

 

GRANTEE     OWNER   TABLE_NAME      PRIVILEGE   GRANTABLE   ROLE

---------- -------- --------------- ------------ ---------- ---------------

SCOTT      HR       EMPLOYEES       SELECT      NO          HR_CLERK

SCOTT      HR       JOBS            SELECT      NO          JOB_MAINT

SCOTT     HR       JOBS            UPDATE      NO          JOB_MAINT

SCOTT      SYS      AUD$            DELETE     NO          DELETE_CATA

LOG_ROLE

SCOTT      SYS      FGA_LOG$        DELETE      NO          DELETE_CATA

LOG_ROLE

在SCOTT的权限中,注意他具有HR.EMPLOYEES表上的SELECT权限,该权限不仅直接通过grant命令授予,而且还通过角色授予。取消其中一个权限不会影响SCOTT对HR.EMPLOYEES表的访问,除非同时删除这两个权限。

109.3.5  使用VPD实现应用程序安全策略

虚拟专用数据库(Virtual Private Database(,VPD) 将服务器实施的细粒度访问控制和安全应用程序上下文结合起来。支持上下文的函数返回一个谓词,即where子句,该子句自动附加到所有的select语句 或其他DML语句。换句话说,由VPD控制的表、视图、同义词上的select语句将根据where子句返回行的子集,该子句由通过应用程序上下文生效的 安全策略函数自动生成。VPD的主要组成部分是行级别的安全性(RLS),也称为“细粒度的访问控制”(FGAC)。

因为VPD在语句解析期间透明地生成谓词,因此可以一致地实施安全策略,而无论无论用户是否正在运行特别的查询、检索应用程序中的数据或者查看Oracle Forms中的数据,都可以一致地实施安全策略。因为Oracle Server在解析时将谓词应用于语句,所以应用程序不需要使用特殊的表、视图等来实现该策略。因此,Oracle可以使用索引、物化视图和并行操作来优化查询,而以其他的方式则不能够进行优化。因此,相比于使用应用程序或其他方式过滤结果的查询,使用VPD可能会产生较少的系统开销。

从维护的角度来看,安全策略可以在安全函数中定义, 使用角色和权限很难创建这种安全函数。类似地,应用程序服务器提供商(Application Server Provider,ASP)可能只需要建立一个数据库来为相同应用程序的多个客户服务,使用VPD策略来确保一个顾客的雇员只可以查看他们自己的数据。 DBA可以使用少量的VPD策略维护一个较大的数据库,而不是针对每个客户都使用一个单独的数据库。

Oracle 10g中的新增内容是列级别的VPD操作。使用列级别的VPD,DBA可以约束对表中特定列的访问。查询返回相同数量的行,但如果用户的上下文不允许访问列,则在约束的列中返回NULL值。

VPD策略可以是静态的、上下文相关的或动态的。静态的或上下文相关的VPD策略是Oracle Database 10g的新增内容,它们可以极大地改进性能,因为它们不需要在每次运行查询时调用策略函数,这是由于在会话中将其缓存以方便以后后面的使用。在Oracle Database 10g之前,所有的策略都是动态的。换句话说,每次解析包含目标VPD表的SQL语句时都运行策略函数。每次登录,在注册期间估计静态策略都要评估一次一次,并且在整个会话期间保持缓存,而不考虑应用程序上下文。使用上下文相关的策略时,如果应用程序上下文改变,则在语句解析时调用策略函数:例如,实施“雇员只可以看到他们自己的薪水历史记录,但经理可以看到他们雇员的所有薪水情况”这种业务规则的策略。如果执行语句的雇员没有改变,就不需要再次调用策略函数,从而减少由于VPD策略实施而产生的系统开销量。

可以使用create context命令创建应用程序上下文,并且使用程序包DBMS_RLS管理VPD策略。可以像其他任何函数一样创建用于返回谓词以实施策略的函数,但这种函数具有两个必需的参数,并且返回一个VARCHAR2。本章后面将详细介绍这些函数,并且使用在Oracle数据库安装期间提供的示例模式来创建一个VPD示例。

1. 应用程序上下文

使用create context命令,可以创建应用程序定义的属性的名称,这些属性用于实施安全策略。此外,还可以定义函数和过程的程序包名称,这些函数和过程用于设置用户会话的安全上下文。下面是示例:

create context hr_security using vpd.emp_access;

create or replace package emp_access as

    procedure set_security_parameters;

end;

create context hr_security using vpd.emp_access;

create or replace package emp_access as

procedure set_security_parameters;

在该示例中,上下文名称是HR_SECURITY,用于在会话期间为用户建立特征或属性的程序包称为EMP_ACCESS。在登录触发器中调用过程SET_SECURITY_PARAMETERS。因为上下文HR_SECURITY只绑定到EMP_ACCESS,因此没有其他的过程可以改变会话属性。这可以确保产生安全的应用程序上下文,在连接到数据库后用户或任何其他进程都不可以改变安全的应用程序上下文该上下文。

 

在用于实现应用程序上下文的一般典型程序包中,使用内置的上下文USERENV来检索有关用户会话自身的信息。在表109-13中是USERENV上下文中一些更为常见的参数。

表109-13  常见的USERENV上下文参数

参    数

返  回  值

CURRENT_SCHEMA

会话的默认模式

DB_NAME

在初始参数DB_NAME中指定的数据库名称

HOST

用户连接的主机名称

IP_ADDRESS

用户连接的IP地址

OS_USER

初始化数据库会话的操作系统账户

SESSION_USER

经过验证的数据库用户名

例如,下面对SYS_CONTEXT的调用将检索数据库会话的用户名和IP_ADDRESS:

declare

     username        varchar2(30);

     ip_addr         varchar2(30);

begin

     username := SYS_CONTEXT('USERENV','SESSION_USER');

     ip_addr := SYS_CONTEXT('USERENV','IP_ADDRESS');

     -- other processing here

end;

declare

username          varchar2(30);

ip_addr             varchar2(30);

begin

username := SYS_CONTEXT('USERENV','SESSION_USER');

ip_addr := SYS_CONTEXT('USERENV','IP_ADDRESS');

-- other processing here

类似地,可以在SQL select语句中使用SYS_CONTEXT函数:

SQL> select SYS_CONTEXT('USERENV','SESSION_USER') username from dual;

USERNAME

-------------------------

KSHELTON

SQL> select SYS_CONTEXT('USERENV','SESSION_USER') username from dual;

 

USERNAME

-------------------------

使用USERENV上下文和数据库中授权信息的一些组合,可以使用DBMS_SESSION.SET_ CONTEXT,将值赋予所创建的应用程序上下文中的参数:

dbms_session.set_context('HR_SECURITY','SEC_LEVEL','HIGH');

在该示例中,应用程序上下文变量SEC_LEVEL在HR_SECURITY上下文中设置为HIGH。可以根据大量条件来分配该值,包括根据用户ID来分配安全级别的映射表。

为了确保针对每个会话设置上下文变量,可以使用登录触发器来调用与该上下文关联的过程。前面提及,在分配的程序包中只可以设置或改变上下文中的变量。下面是一个示例的登录触发器,该触发器调用过程以建立上下文:

create or replace trigger vpd.set_security_parameters

   after logon on database

begin

   vpd.emp_access.set_security_parameters;

end;

create or replace trigger vpd.set_security_parameters

after logon on database

begin

vpd.emp_access.set_security_parameters;

在该示例中,过程SET_SECURITY_PARAMETERS将需要调用DBMS_SESSION.SET_ CONTEXT。

在Oracle Enterprise Manager中,可以使用Policy Manager来建立上下文和策略组,如图109-8所示。

image058.jpg

图109-8  Oracle Policy Manager

2. 安全策略实现

一旦基础结构到位之后在适当的位置,从而就可以建立安全环境,下一步就是定义用于生成谓词的函数,这些谓词将附加到每个针对受保护表的每个select 语句或DML命令。用于实现谓词生成的函数有2个参数:受保护对象的拥有者、拥有者模式中对象的名称。一个函数只可以处理一种操作类型的谓词生成,例如 select,或者可以适用于所有的DML命令,这取决于该函数如何关联受保护的表。下面的示例显示了包含两个函数的程序包主体:一个函数将用于控制 select语句中的访问,另一个函数将用于任何其他的DML语句:

create or replace package body get_predicates is

   function emp_select_restrict(owner varchar2, object_name varchar2)

          return varchar2 is

      ret_predicate    varchar2(1000);  -- part of WHERE clause

   begin

      -- only allow certain employees to see rows in the table

      -- . . . check context variables and build predicate

      return ret_predicate;

   end emp_select_restrict;

   function emp_dml_restrict(owner varchar2, object_name varchar2)

          return varchar2 is

      ret_predicate    varchar2(1000);  -- part of WHERE clause

   begin

      -- only allow certain employees to make changes to the table

      -- . . . check context variables and build predicate

      return ret_predicate;

   end emp_dml_restrict;

end; -- package body

create or replace package body get_predicates is

function emp_select_restrict(owner varchar2, object_name varchar2)

return varchar2 is

ret_predicate varchar2(1000); -- part of WHERE clause

begin

-- only allow certain employees to see rows in the table

-- . . . check context variables and build predicate

return ret_predicate;

end emp_select_restrict;

function emp_dml_restrict(owner varchar2, object_name varchar2)

return varchar2 is

ret_predicate varchar2(1000); -- part of WHERE clause

begin

-- only allow certain employees to make changes to the table

-- . . . check context variables and build predicate

return ret_predicate;

end emp_dml_restrict;

每个函数返回一个包含表达式的字符串,该表达式被添加到select语句或DML命令的where子句。用户或应用程序永远不会看到这个WHERE子句的值,它在解析时自动添加到该命令。

开发人员必须确保这些函数总是返回有效的表达式。否则,任何对受保护表的访问将总是会失败,如同下面的示例所示:

SQL> select * from hr.employees;

select * from hr.employees

                 *

ERROR at line 1:

ORA-28113: policy predicate has error

SQL> select * from hr.employees;

select * from hr.employees

*

ERROR at line 1:

错误消息不会表明谓词是什么,并且所有的用户都无法访问表,直到修正谓词函数。本章后面将介绍关于如何调试谓词函数的技巧。

3. 使用DBMS_RLS

内置的程序包DBMS_RLS包含大量子程序,DBA使用这些子程序维护与表、视图和同义词关联的安全策略。表109-14列出了程序包DBMS_RLS中的子程序。任何需要创建和管理策略的用户都必须被授予程序包SYS.DBMS_RLS上的EXECUTE权限。

表109-14  DBMS_RLS程序包的子程序

子  程  序

说    明

ADD_POLICY

将细粒度的访问控制策略添加到对象

DROP_POLICY

删除对象中的FGAC策略

REFRESH_POLICY

重新解析与策略关联的、缓存的所有语句

ENABLE_POLICY

启用或禁用FGAC策略

CREATE_POLICY_GROUP

创建策略组

ADD_GROUPED_POLICY

将策略添加到策略组

ADD_POLICY_CONTEXT

添加当前应用程序的上下文

DELETE_POLICY_GROUP

删除策略组

DROP_GROUPED_POLICY

从策略组中删除一个策略

DROP_POLICY_CONTEXT

删除活动应用程序的上下文

ENABLE_GROUPED_POLICY

启用或禁用组策略

DISABLE_GROUPED_POLICY

禁用组策略

REFRESH_GROUPED_POLICY

重新解析与策略组关联的、缓存的所有语句

本章中将介绍最常用的子程序,ADD_POLICY和DROP_POLICY。ADD_POLICY的语法如下:

DBMS_RLS.ADD_POLICY

(

     object_schema          IN varchar2 null,

     object_name            IN varchar2,

     policy_name            IN varchar2,

     function_schema        IN varchar2 null,

     policy_function        IN varchar2,

     statement_types        IN varchar2 null,

     update_check           IN boolean false,

     enable                   IN boolean true,

     static_policy          IN boolean false,

     policy_type            IN binary_integer null,

     long_predicate         IN in Boolean false,

     sec_relevant_cols     IN varchar2,

     sec_relevant_cols_opt  IN binary_integer null

);

DBMS_RLS.ADD_POLICY

(

object_schema                           IN varchar2 null,

object_name                               IN varchar2,

policy_name                               IN varchar2,

function_schema                        IN varchar2 null,

policy_function                       IN varchar2,

statement_types                        IN varchar2 null,

update_check                             IN boolean false,

enable                                        IN boolean true,

static_policy                           IN boolean false,

policy_type                              IN binary_integer null,

long_predicate                        IN in Boolean false,

sec_relevant_cols                    IN varchar2,

sec_relevant_cols_opt              IN binary_integer null

注意,其中一些参数具有BOOLEAN默认值,并且较少使用的参数都在参数列表的末端。对于绝大多数情况来说,这就使对DBMS_RLS.ADD_POLICY的特定调用的语法更易于编写和理解。表109-15提供了每个参数的说明和用法。

表109-15  DBMS_RLS.ADD_POLICY的参数

参    数

说    明

object_schema

包含由策略保护的表、视图或同义词的模式。如果该值是NULL,则使用调用过程的用户的模式

object_name

由策略保护的表、视图或同义词的名称

policy_name

添加到该对象的策略的名称。对于受保护的每个对象,该策略名必须唯一

function_schema

拥有策略函数的模式;如果该值为NULL,则使用调用过程的用户的模式

policy_function

函数名称,该函数为针对object_name的策略生成谓词。如果函数是程序包的一部分,则在此处必须也指定程序包名,用于限定策略函数名

statement_types

应用策略的语句类型。允许的值(以逗号分隔)可以是SELECT、INSERT、UPDATE、DELETE和INDEX的任意组合。默认情况下,除了INDEX之外的所有类型都适用

update_check

对于INSERT或UPDATE类型,该参数是可选项,它默认为FALSE。如果该参数为TRUE,则在检查SELECT或DELETE操作时,则该策略也对INSERT或UPDATE语句也要进行检查该策略

enable

该参数默认为TRUE,表明添加该策略时是否启用它

static_policy

如果该参数为TRUE,该策略为任何访问该对象的人产生相同的谓词字符串,除了SYS用户或具有EXEMPT ACCESS POLICY权限的任何用户。该参数的默认值为FALSE

policy_type

如果该值不是NULL,则覆盖static_policy。可允许的值是STATIC、SHARED_STATIC、CONTEXT_SENSITIVE、SHARED_CONTEXT_SENSITIVE和DYNAMIC

long_predicate

该参数默认为FALSE。如果它为TRUE,谓词字符串最多可为32K字节长。否则,限制为4000字节

sec_relevant_cols

实施列级别的VPD,这是Oracle 10g的新增内容。只应用于表和视图。在列表中指定受保护的列,使用逗号或空格作为分隔符。该策略只应用于指定的敏感的列位于查询或DML语句中时。默认情况下,所有的列都是受保护的

sec_relevant_cols_opt

允许在列级别VPD过滤查询中的行仍然出现在结果集中,这些行具有为每个敏感列返回的NULL值。该参数的默认值为NULL;如果不是默认值,则必须指定DBMS_RLS.ALL_ROWS,用于显示具有针对敏感列为的NULL值的所有列

如果不介意用户是否会看到行的部分内容,其实只是看不到而只关心包含机密信息的列,例如Social Security Number(社会保障号)或薪水情况,则使用参数sec_relevant_cols非常便利。在本章后面的示例中,将根据定义的第一个安全策略对来过滤公司大多数雇员过滤的敏感数据。

在下面的示例中,将名为 EMP_SELECT_RESTRICT的策略应用于表HR.EMPLOYEES。模式VPD拥有策略函数 get_predicates.emp_select_restrict。该策略显式地应用于表上的SELECT语句。然而,将UPDATE_CHECK 设置为TRUE时,在更新行或将行插入到表中时,也会检查update或delete命令:

dbms_rls.add_policy (

         object_schema =>     'HR',

         object_name =>       'EMPLOYEES',

         policy_name =>       'EMP_SELECT_RESTRICT',

         function_schema => 'VPD',

         policy_function => 'get_predicates.emp_select_restrict',

         statement_types => 'SELECT',

         update_check =>      TRUE,

         enable =>             TRUE

);

dbms_rls.add_policy (

object_schema =>       'HR',

object_name =>          'EMPLOYEES',

policy_name =>          'EMP_SELECT_RESTRICT',

function_schema => 'VPD',

policy_function => 'get_predicates.emp_select_restrict',

statement_types =>   'SELECT',

update_check =>        TRUE,

enable =>                   TRUE

因为没有设置static_policy,它默认为FALSE,这意味着该策略是动态的,并且在每次解析select语句时检查该策略。这是在Oracle Database 10g之前唯一可用的行为。

使用子程序ENABLE_POLICY是临时禁用策略的一种简单方法,并且不需要在以后后面将策略重新绑定到表:

dbms_rls.enable_policy(

         object_schema =>   'HR',

         object_name =>     'EMPLOYEES',

         policy_name =>     'EMP_SELECT_RESTRICT',

         enable =>          FALSE

);

dbms_rls.enable_policy(

object_schema =>   'HR',

object_name =>      'EMPLOYEES',

policy_name =>      'EMP_SELECT_RESTRICT',

enable =>               FALSE

如果为相同的对象指定多个策略,则在每个谓词之间添加AND条件。如果需要在多个策略的谓词之间使用OR条件,则很可能需要修订策略。每个策略的逻辑需要整结合到在一个策略中,该策略在谓词的每个部分之间具有OR条件。

4. 创建VPD

本节将从头到尾遍历VPD的完整实现,该示例依赖于和Oracle Database 10g和11g一起安装的示例模式。具体来说,将实现HR.EMPLOYEES表上的FGAC策略,用于根据经理状态地位和雇员的部门编号来限制访问。如果是雇员,可以在HR.EMPLOYEES中看到自己的行;如果是经理,则可以看到他直接管理直接向该经理报告的所有雇员的行。

提示:

如果没有在数据库中安装示例模式,可以使用$ORACLE_HOME/demo/schema中的脚本创建它们。

一旦示例模式到位之后在适当的位置,需要在数据库中创建一些用户,他们想要查看希望看到表HR.EMPLOYEES中的行的用户:

create user smavris identified by smavris702;

grant connect, resource to smavris;

create user dgrant identified by dgrant507;

grant connect, resource to dgrant;

create user kmourgos identified by kmourgos622;

grant connect, resource to kmourgos;

create user smavris identified by smavris702;

grant connect, resource to smavris;

 

create user dgrant identified by dgrant507;

grant connect, resource to dgrant;

 

create user kmourgos identified by kmourgos622;

用户KMOURGOS是所有存货管理员的经理,而DGRANT是KMOURGOS的一个雇员。用户SMAVRIS是公司的HR_REP。

在下面的3个步骤中,将HR.EMPLOYEES表上的SELECT权限授予数据库中的每个人,并且将创建一个查找表,将雇员ID号映射到他们的数据库账户。设置用户会话上下文变量的过程将使用该表把雇员ID号赋予上下文变量,在策略函数中将使用该上下文变量来生成谓词。

grant select on hr.employees to public;

create table hr.emp_login_map (employee_id, login_acct)

   as select employee_id, email from hr.employees;

grant select on hr.emp_login_map to public;

grant select on hr.employees to public;

 

create table hr.emp_login_map (employee_id, login_acct)

as select employee_id, email from hr.employees;

 

接下来,创建称为VPD的用户账户,该账户具有创建上下文和维护策略函数的权限:

create user vpd identified by vpd439;

grant connect, resource, create any context, create public synonym to vpd;

create user vpd identified by vpd439;

连接到VPD模式,创建称为HR_SECURITY的上下文,并且定义用于设置应用程序上下文的程序包和过程:

connect vpd/vpd439@dw;

create context hr_security using vpd.emp_access;

create or replace package vpd.emp_access as

    procedure set_security_parameters;

end;

connect vpd/vpd439@dw;

 

create context hr_security using vpd.emp_access;

 

create or replace package vpd.emp_access as

procedure set_security_parameters;

记住,程序包VPD.EMP_ACCESS中的过程是可以设置上下文变量的唯一过程。VPD.EMP_ACCESS的程序包主体如下:

create or replace package body vpd.emp_access is

--

-- At user login, run set_security_parameters to

-- retrieve the user login name, which corresponds to the EMAIL

-- column in the table HR.EMPLOYEES.

--

-- context USERENV is pre-defined for user characteristics such

-- as username, IP address from which the connection is made,

-- and so forth.

--

-- for this procedure, we are only using SESSION_USER

-- from the USERENV context.

--

   procedure set_security_parameters is

      emp_id_num      number;

      emp_login       varchar2(50);

   begin

      -- database username corresponds to email address in HR.EMPLOYEES

      emp_login := sys_context('USERENV','SESSION_USER');

      dbms_session.set_context('HR_SECURITY','USERNAME',emp_login);

      -- get employee id number, so manager rights can be established

      -- but don't bomb out other DB users who are not in the

      -- EMPLOYEES table

      begin

         select employee_id into emp_id_num

            from hr.emp_login_map where login_acct = emp_login;

         dbms_session.set_context('HR_SECURITY','EMP_ID',emp_id_num);

      exception

         when no_data_found then

            dbms_session.set_context('HR_SECURITY','EMP_ID',0);

      end;

      -- Future queries will restrict rows based on emp_id

   end; -- procedure

end; -- package body

create or replace package body vpd.emp_access is

 

--

-- At user login, run set_security_parameters to

-- retrieve the user login name, which corresponds to the EMAIL

-- column in the table HR.EMPLOYEES.

--

 

-- context USERENV is pre-defined for user characteristics such

-- as username, IP address from which the connection is made,

-- and so forth.

--

-- for this procedure, we are only using SESSION_USER

-- from the USERENV context.

--

procedure set_security_parameters is

emp_id_num number;

emp_login varchar2(50);

begin

 

-- database username corresponds to email address in HR.EMPLOYEES

emp_login := sys_context('USERENV','SESSION_USER');

 

dbms_session.set_context('HR_SECURITY','USERNAME',emp_login);

-- get employee id number, so manager rights can be established

-- but don't bomb out other DB users who are not in the

-- EMPLOYEES table

begin

select employee_id into emp_id_num

from hr.emp_login_map where login_acct = emp_login;

 

dbms_session.set_context('HR_SECURITY','EMP_ID',emp_id_num);

exception

when no_data_found then

dbms_session.set_context('HR_SECURITY','EMP_ID',0);

end;

 

-- Future queries will restrict rows based on emp_id

 

end; -- procedure

 

有关该过程还需要注意一些事情。我们通过查询USERENV上下文来检索用户的模式,默认情况下为所有的用户自动启用该上下文。然后,将该模式赋给新创建的上下文HR_SECURITY中的变量USERNAME。通过在映射表HR.EMP_LOGIN_MAP中进行查找来确定另一个HR_SECURITY上下文变量EMP_ID。不希望该过程在已注册登录的用户不在映射表中时中断,并且显示一个错误。相反,分配EMP_ID的值为0,结果就是在策略函数中生成谓词时没有对HR.EMPLOYEES表的任何访问。

在下面的步骤中,授予数据库中每个人程序包上的EXECUTE权限,并且为其创建一个同义词,从而在每次需要调用它时节省一些击键次数:

grant execute on vpd.emp_access to PUBLIC;

create public synonym emp_access for vpd.emp_access;

grant execute on vpd.emp_access to PUBLIC;

为了确保在每个用户登录时为其定义上下文,我们将以SYSTEM身份连接到数据库作为SYS连接,并且创建一个登录触发器,用于在上下文中建立设置变量:

connect system/nolongermanager@dw as sysdba;

create or replace trigger vpd.set_security_parameters

   after logon on database

begin

   vpd.emp_access.set_security_parameters;

end;

connect sys/sys727@dw as sysdba;

 

create or replace trigger vpd.set_security_parameters

after logon on database

begin

vpd.emp_access.set_security_parameters;

因为为每个连接到数据库的用户激活该触发器,所以如果不是为每个用户测试代码的话,则极其重要的方面是为每一类的用户测试代码就极其重要,如果没有为数据库中的每个用户激活该触发器的话!如果触发器失败并且显示一个错误,那么非SYSDBA的常规用户将无法注册登录。

到目前为止,已经有了定义的了上下文、用来设置建立上下文变量的过程以及自动调用该过程的触发器。作为前面定义的3个用户中的一个进行登录,可以查询上下文的内容:

SQL> connect smavris/smavris702@dw

Connected.

SQL> select * from session_context;

NAMESPACE                ATTRIBUTE                 VALUE

------------------------ ------------------------- ---------------------

HR_SECURITY              USERNAME                  SMAVRIS

HR_SECURITY              EMP_ID                    203

2 rows selected.

SQL> connect smavris/smavris702@dw

Connected.

 

SQL> select * from session_context;

 

NAMESPACE               ATTRIBUTE                VALUE

------------------------ ------------------------- ---------------------

HR_SECURITY             USERNAME                 SMAVRIS

HR_SECURITY             EMP_ID                   203

 

注意当SMAVRIS尝试冒充另一个雇员时发生的情况:

 

SQL> begin

  2    dbms_session.set_context('HR_SECURITY','EMP_ID',100);

  3  end;

begin

*

ERROR at line 1:

ORA-01031: insufficient privileges

ORA-06512: at "SYS.DBMS_SESSION", line 94

ORA-06512: at line 2

SQL> begin

2 dbms_session.set_context('HR_SECURITY','EMP_ID',100);

3 end;

 

begin

*

ERROR at line 1:

ORA-01031: insufficient privileges

ORA-06512: at "SYS.DBMS_SESSION", line 82

只允许程序包VPD.EMP_ACCESS设置或改变上下文中的变量。

最后的步骤包括定义将生成谓词的过程,以及将其中的一个或多个这些过程赋给HR.EMPLOYEES表。作为用户VPD,该用户已经拥有了上下文过程,接下来建立定义谓词的程序包:

connect vpd/vpd439@dw;

create or replace package vpd.get_predicates as

   -- note -- security function ALWAYS has two parameters,

   -- table owner name and table name

   function emp_select_restrict

       (owner varchar2, object_name varchar2) return varchar2;

   -- other functions can be written here for INSERT, DELETE, and so forth.

end get_predicates;

create or replace package body vpd.get_predicates is

   function emp_select_restrict

      (owner varchar2, object_name varchar2) return varchar2 is

      ret_predicate    varchar2(1000);  -- part of WHERE clause

   begin

      -- only allow employee to see their row or immediate subordinates

      ret_predicate := 'EMPLOYEE_ID = ' ||

                          sys_context('HR_SECURITY','EMP_ID') ||

                          ' OR MANAGER_ID = ' ||

                          sys_context('HR_SECURITY','EMP_ID');

      return ret_predicate;

   end emp_select_restrict;

end; -- package body

connect vpd/vpd439@dw;

 

create or replace package vpd.get_predicates as

 

-- note: security function ALWAYS has two parameters,

-- table owner name and table name

 

function emp_select_restrict

(owner varchar2, object_name varchar2) return varchar2;

 

-- other functions can be written here for INSERT, DELETE, and so forth.

 

end get_predicates;

 

 

create or replace package body vpd.get_predicates is

 

function emp_select_restrict

(owner varchar2, object_name varchar2) return varchar2 is

 

ret_predicate varchar2(1000); -- part of WHERE clause

 

begin

-- only allow employee to see their row or immediate subordinates

ret_predicate := 'EMPLOYEE_ID = ' ||

sys_context('HR_SECURITY','EMP_ID') ||

' OR MANAGER_ID = ' ||

sys_context('HR_SECURITY','EMP_ID');

return ret_predicate;

end emp_select_restrict;

 

一旦使用DBMS_RLS将该函数附加到表,将生成一个文本字符串,在每次访问表时将该文本字符串用于WHERE子句中。该字符串总是类似于:

EMPLOYEE_ID = 124 OR MANAGER_ID = 124

和建立上下文环境的程序包一样,需要允许用户访问该程序包:

grant execute on vpd.get_predicates to PUBLIC;

create public synonym get_predicates for vpd.get_predicates;

grant execute on vpd.get_predicates to PUBLIC;

最后(但并不是最不重要的方面),使用DBMS_RLS.ADD_POLICY过程将策略函数附加  到表:

dbms_rls.add_policy (

         object_schema =>   'HR',

         object_name =>     'EMPLOYEES',

         policy_name =>     'EMP_SELECT_RESTRICT',

         function_schema => 'VPD',

         policy_function => 'get_predicates.emp_select_restrict',

         statement_types => 'SELECT',

         update_check =>    TRUE,

         enable =>          TRUE

);

dbms_rls.add_policy (

object_schema =>       'HR',

object_name =>          'EMPLOYEES',

policy_name =>          'EMP_SELECT_RESTRICT',

function_schema => 'VPD',

policy_function => 'get_predicates.emp_select_restrict',

statement_types =>   'SELECT',

update_check =>        TRUE,

enable =>                   TRUE

雇员可以像前面一样访问HR.EMPLOYEES表,但他们将只能看到自己的行,以及为其工作的雇员的行(如果存在这种雇员的话)。作为KMOURGOS注册登录,尝试检索HR.EMPLOYEES表的所有行,但只可以看到KMOURGOS的行以及他直接管理直接向其报告的雇员的行:

SQL> connect kmourgos/kmourgos622@dw;

Connected.

SQL> select employee_id, first_name, last_name,

  2         email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME LAST_NAME   EMAIL      JOB_ID      SALARY MANAGER_ID

----------- ---------- ----------   --------- --------- ------- ----------

        124   Kevin      Mourgos     KMOURGOS   ST_MAN       5800       100

        141   Trenna     Rajs          TRAJS      ST_CLERK     3500       124

        142   Curtis     Davies      CDAVIES    ST_CLERK     3100       124

        143   Randall   Matos       RMATOS     ST_CLERK     2600       124

        144   Peter      Vargas      PVARGAS    ST_CLERK     2500       124

        196   Alana      Walsh       AWALSH     SH_CLERK     3100       124

        197   Kevin      Feeney      KFEENEY    SH_CLERK     3000       124

        198   Donald     OConnell    DOCONNEL   SH_CLERK     2600       124

        199   Douglas    Grant       DGRANT     SH_CLERK     2600       124

9 rows selected.

SQL> connect kmourgos/kmourgos622@dw;

Connected.

SQL> select employee_id, first_name, last_name,

2           email, job_id, salary, manager_id from hr.employees;

 

EMPLOYEE_ID FIRST_NAME LAST_NAME    EMAIL       JOB_ID      SALARY MANAGER_ID

----------- ---------- ----------- ---------- ---------- ------- ----------

124 Kevin       Mourgos     KMOURGOS    ST_MAN        5800          100

141 Trenna      Rajs         TRAJS       ST_CLERK      3500          124

142 Curtis      Davies      CDAVIES     ST_CLERK      3100          124

143 Randall     Matos       RMATOS      ST_CLERK      2600          124

144 Peter       Vargas      PVARGAS     ST_CLERK      2500        124

196 Alana       Walsh       AWALSH      SH_CLERK      3100          124

197 Kevin       Feeney      KFEENEY     SH_CLERK      3000          124

198 Donald      OConnell    DOCONNEL    SH_CLERK      2600          124

199 Douglas     Grant       DGRANT      SH_CLERK      2600          124

对于用户DGRANT,情况则完全不同:

SQL> connect dgrant/dgrant507@dw;

Connected.

SQL> select employee_id, first_name, last_name,

  2         email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL     JOB_ID     SALARY   MANAGER_ID

----------- ---------- --------- -------- --------- ------- ----------

        199   Douglas    Grant      DGRANT    SH_CLERK    2600        124

1 row selected.

SQL> connect dgrant/dgrant507@dw;

Connected.

SQL> select employee_id, first_name, last_name,

2         email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME LAST_NAME   EMAIL     JOB_ID     SALARY   MANAGER_ID

----------- ---------- ----------- ---------- ---------- ------- ----------

199    Douglas Grant     DGRANT     SH_CLERK   2600     124

DGRANT开始只能看到自己的行,因为他不管理公司内的其他任何人。

在SMAVRIS的情况中,可以通过查询看到类似的结果:

SQL> connect smavris/smavris702@dw;

Connected.

SQL> select employee_id, first_name, last_name,

  2         email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME LAST_NAME    EMAIL      JOB_ID      SALARY MANAGER_ID

----------- ---------- ------------ ---------- ---------- ------- ----------

        203 Susan      Mavris       SMAVRIS    HR_REP        6500        101

1 row selected.

SQL> connect smavris/smavris702@dw;

Connected.

SQL> select employee_id, first_name, last_name,

2           email, job_id, salary, manager_id from hr.employees;

 

EMPLOYEE_ID FIRST_NAME LAST_NAME    EMAIL      JOB_ID      SALARY MANAGER_ID

----------- ---------- ------------ ---------- ---------- ------- ----------

203 Susan      Mavris      SMAVRIS     HR_REP      6500          101

但是需要注意,SMAVRIS属于人力资源(HR)部门,所以应 该能够看到表中的所有行。此外,SMAVRIS应该是可以查看所有雇员薪水信息的唯一的人。因此,需要改变策略函数,为SMAVRIS和HR部门中的其他 雇员提供对HR.EMPLOYEES表的完全访问。此外,可以使用策略赋值中列级别的约束来返回相同数量的行,但其中的敏感数据作为NULL值返回。

为了方便HR部门的雇员对HR.EMPLOYEES表的访问,首先需要改变映射表,使其包括JOB_ID列。如果JOB_ID列的值是具有HR_REP的值,该雇员就属于HR部门。首先禁止该策略生效,并且创建新的映射表:

SQL> begin

  2    dbms_rls.enable_policy(

  3          object_schema =>   'HR',

  4          object_name =>     'EMPLOYEES',

  5          policy_name =>     'EMP_SELECT_RESTRICT',

  6          enable =>          FALSE

  7       );

  8  end;

PL/SQL procedure successfully completed.

SQL> drop table hr.emp_login_map;

Table dropped.

SQL> create table hr.emp_login_map (employee_id, login_acct, job_id)

  2    as select employee_id, email, job_id from hr.employees;

Table created.

SQL> grant select on hr.emp_login_map to public;

Grant succeeded.

SQL> begin

2    dbms_rls.enable_policy(

3          object_schema => 'HR',

4          object_name =>       'EMPLOYEES',

5          policy_name =>     'EMP_SELECT_RESTRICT',

6          enable =>              FALSE

7       );

8 end;

PL/SQL procedure successfully completed.

SQL> drop table hr.emp_login_map;

Table dropped.

 

SQL> create table hr.emp_login_map (employee_id, login_acct, job_id)

2    as select employee_id, email, job_id from hr.employees;

Table created.

 

SQL> grant select on hr.emp_login_map to public;

用于建立设置上下文变量的过程VPD.EMP_ACCESS需要添加另一个上下文变量,该上下文变量表明访问表的用户的安全级别。改变SELECT语句,并且对DBMS_SESSION.SET_CONTEXT进行另一次调用,如下所示:

. . .

      emp_job_id      varchar2(50);

. . .

         select employee_id, job_id into emp_id_num, emp_job_id

            from hr.emp_login_map where login_acct = emp_login;

         dbms_session.set_context('HR_SECURITY','SEC_LEVEL',

             case emp_job_id when 'HR_REP' then 'HIGH' else 'NORMAL' end );

. . .

. . .

emp_job_id varchar2(50);

. . .

select employee_id, job_id into emp_id_num, emp_job_id

from hr.emp_login_map where login_acct = emp_login;

 

dbms_session.set_context('HR_SECURITY','SEC_LEVEL',

case emp_job_id when 'HR_REP' then 'HIGH' else 'NORMAL' end );

当雇员具有HR_REP的职称职位时,将上下文变量SEC_LEVEL设置为HIGH而不是NORMAL。在策略函数中,需要检查这个新的条件,如下所示:

create or replace package body vpd.get_predicates is

   function emp_select_restrict

      (owner varchar2, object_name varchar2) return varchar2 is

      ret_predicate    varchar2(1000);  -- part of WHERE clause

   begin

      -- only allow employee to see their row or immediate subordinates,

      -- unless they have high security clearance

      if sys_context('HR_SECURITY','SEC_LEVEL') = 'HIGH' then

         ret_predicate := '';  -- no restrictions in WHERE clause

      else

         ret_predicate := 'EMPLOYEE_ID = ' ||

                          sys_context('HR_SECURITY','EMP_ID') ||

                          ' OR MANAGER_ID = ' ||

                          sys_context('HR_SECURITY','EMP_ID');

      end if;

      return ret_predicate;

   end emp_select_restrict;

end; -- package body

create or replace package body vpd.get_predicates is

function emp_select_restrict

(owner varchar2, object_name varchar2) return varchar2 is

 

ret_predicate varchar2(1000); -- part of WHERE clause

 

begin

-- only allow employee to see their row or immediate subordinates,

-- unless they have high security clearance

if sys_context('HR_SECURITY','SEC_LEVEL') = 'HIGH' then

ret_predicate := ''; -- no restrictions in WHERE clause

else

ret_predicate := 'EMPLOYEE_ID = ' ||

sys_context('HR_SECURITY','EMP_ID') ||

' OR MANAGER_ID = ' ||

sys_context('HR_SECURITY','EMP_ID');

end if;

return ret_predicate;

end emp_select_restrict;

 

因为策略是动态的,因此每次执行SELECT语句时都生成谓词,从而不需要进行策略刷新。当用户SMAVRIS,即HR部门的代表,现在运行查询时,可以看到HR.EMPLOYEES表中的所有行:

SQL> connect smavris/smavris702@dw;

Connected.

SQL> select employee_id, first_name, last_name,

  2         email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME  LAST_NAME   EMAIL      JOB_ID       SALARY MANAGER_ID

----------- ----------- ---------   --------- ----------  ------- ----------

        100 Steven      King          SKING      AD_PRES      24000

        101 Neena       Kochhar     NKOCHHAR   AD_VP      17000        100

. . .

        204 Hermann     Baer          HBAER      PR_REP       10000        101

        205 Shelley     Higgins     SHIGGINS   AC_MGR      12000        101

        206 William     Gietz       WGIETZ     AC_ACCOUNT  8300        205

107 rows selected.

SQL> connect smavris/smavris702@dw;

Connected.

SQL> select employee_id, first_name, last_name,

2>          email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME   LAST_NAME   EMAIL      JOB_ID     SALARY   MANAGER_ID

----------- ----------- ----------- ---------- ---------- ------- ----------

100 Steven      King        SKING      AD_PRES    24000

101 Neena       Kochhar     NKOCHHAR    AD_VP       17000       100

. . .

204 Hermann     Baer        HBAER      PR_REP     10000        101

205 Shelley     Higgins     SHIGGINS    AC_MGR      12000       101

206 William     Gietz      WGIETZ      AC_ACCOUNT   8300        205

SMAVRIS在HR_SECURITY上下文中的安全级别是HIGH:

SQL> connect smavris/smavris702

Connected.

SQL> select sys_context('HR_SECURITY','SEC_LEVEL') from dual;

SYS_CONTEXT('HR_SECURITY','SEC_LEVEL')

--------------------------------------------------------------

HIGH

SQL>

然而,DGRANT仍然只可以看到表中自己的行,因为他在HR_SECURITY上下文中的安全级别是NORMAL:

SQL> connect dgrant/dgrant507@dw;

Connected.

SQL> select employee_id, first_name, last_name,

  2         email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME LAST_NAME   EMAIL      JOB_ID      SALARY MANAGER_ID

----------- ---------- ---------- --------- ---------- ------- ----------

        199 Douglas      Grant       DGRANT     SH_CLERK     2600      124

1 row selected.

SQL> select sys_context('HR_SECURITY','SEC_LEVEL') from dual;

SYS_CONTEXT('HR_SECURITY','SEC_LEVEL')

--------------------------------------------------------------

NORMAL

SQL> connect dgrant/dgrant507@dw;

Connected.

SQL> select employee_id, first_name, last_name,

2         email, job_id, salary, manager_id from hr.employees;

 

EMPLOYEE_ID FIRST_NAME LAST_NAME   EMAIL     JOB_ID     SALARY MANAGER_ID

----------- ---------- ----------- ---------- ---------- ------- ----------

199 Douglas     Grant       DGRANT     SH_CLERK   2600    124

 

为了实施只有HR雇员可以看到薪水信息的需求,需要稍微修改策略函数,启用具有列级别约束的策略:

dbms_rls.add_policy (

         object_schema =>   'HR',

         object_name =>     'EMPLOYEES',

         policy_name =>     'EMP_SELECT_RESTRICT',

         function_schema => 'VPD',

         policy_function => 'get_predicates.emp_select_restrict',

         statement_types => 'SELECT',

         update_check =>    TRUE,

         enable =>          TRUE,

         sec_relevant_cols => 'SALARY',

         sec_relevant_cols_opt => dbms_rls.all_rows

);

dbms_rls.add_policy (

object_schema =>       'HR', 

object_name =>          'EMPLOYEES',

policy_name =>          'EMP_SELECT_RESTRICT',

function_schema => 'VPD',

policy_function => 'get_predicates.emp_select_restrict',

statement_types =>   'SELECT',

update_check =>        TRUE,

enable =>                   TRUE,

sec_relevant_cols => 'SALARY',

sec_relevant_cols_opt => dbms_rls.all_rows

最后一 个参数SEC_RELEVANT_COLS_OPT指定程序包常量DBMS_RLS.ALL_ROWS,用于表明仍然希望看到查询结果中的所有行,但是具 有返回NULL值的相关列(在当前情况中是SALARY)。否则,将不会看到包含SALARY列的查询中的任何行。

5. 调试VPD策略

即使没有获得“ORA-28113: policy predicate has error”或“ORA-00936: missing expression”,查看语句解析时生成的实际谓词也会非常有用。有两种方法可调试谓词,这两种方法都各有其优点和缺点。

第一种方法使用动态性能视图V$SQLAREA和V$VPD_POLICY。顾名思义如同其名称所暗示的那样,V$SQLAREA包含当前位于共享池中的SQL语句,以及当前的执行统计。视图V$VPD_POLICY列出当前在数据库中实施的所有策略,以及谓词。连接2个表,如同下面的示例所示,连接2个表,可以提供一些信息,我们需要通过这些信息来帮助调试在查询结果中遇到的任何问题:

SQL> select s.sql_text, v.object_name, v.policy, v.predicate

  2     from v$sqlarea s, v$vpd_policy v

  3     where s.hash_value = v.sql_hash;

SQL_TEXT                  OBJECT_NAM    POLICY                 PREDICATE

---------------------- ----------    ------------------- -----------------

select employee_id, first EMPLOYEES  EMP_SELECT_RESTRICT EMPLOYEE_ID = 199

_name, last_name, email,                                       OR MANAGER_ID = 199

job_id, salary, manager_i

d from hr.employees

select employee_id, first EMPLOYEES  EMP_SELECT_RESTRICT

_name, last_name, email,

job_id, salary, manager_i

d from hr.employees

SQL>

SQL> select s.sql_text, v.object_name, v.policy, v.predicate

2     from v$sqlarea s, v$vpd_policy v

3     where s.hash_value = v.sql_hash;

SQL_TEXT            OBJECT_NAME POLICY              PREDICATE

-------------------- ------------ -------------------- -----------------

select employee_id, EMPLOYEES   EMP_SELECT_RESTRICT

first_name, last_nam

e,      email, job_i

d, salary, manager_i

d from hr.employees

 

select employee_id, EMPLOYEES   EMP_SELECT_RESTRICT EMPLOYEE_ID = 124

first_name, last_nam                                  OR MANAGER_ID =

e, email, job_i                                     124

d, salary, manager_i

d from hr.employees

 

select employee_id, EMPLOYEES   EMP_SELECT_RESTRICT EMPLOYEE_ID = 199

first_name, last_nam                                  OR MANAGER_ID =

e, email, job_i                                     199

d, salary, manager_i

d from hr.employees

 

如果在此查询中将连接添加一个到该查询中的V$SESSION的连接,则可以识别标识哪个用户正在运行SQL。这在第二个SQL语句中尤其重要,此SQL语句没有应用谓词,因此,我们能够推断的只是HR雇员之一运行此查询。该方法的不足之处在于:如果数据库非常忙,则在有机会运行该查询之前,可能由于其他的SQL命令而在共享池中刷新了当前SQL命令。

另一个方法使用alter session命令来生成纯文本的跟踪文件,该文件包含前面查询的许多信息。下面是建立跟踪的命令:

SQL> begin

  2     dbms_rls.refresh_policy;

  3  end;

PL/SQL procedure successfully completed.

SQL> alter session set events '10730 trace name context forever, level 12';

Session altered.

SQL> begin

2      dbms_rls.refresh_policy;

3   end;

PL/SQL procedure successfully completed.

 

SQL> alter session set events '10730 trace name context forever, level 12';

为跟踪RLS策略谓词定义事件10730。其他可以跟踪的常见事件是用于会话登录/退出的10029和10030、用于跟踪位图索引访问的10710、用于模仿重做日志的写入错误的10253,以及其他事件。一旦改变会话,用户DGRANT运行其查询:

SQL> select employee_id, first_name, last_name,

  2      email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME  LAST_NAME   EMAIL      JOB_ID      SALARY MANAGER_ID

----------- ----------- --------- ---------- ---------- ------- ----------

        199   Douglas      Grant       DGRANT     SH_CLERK      2600        124

 

1 row selected.

SQL> select employee_id, first_name, last_name,

2      email, job_id, salary, manager_id from hr.employees;

EMPLOYEE_ID FIRST_NAME LAST_NAME   EMAIL      JOB_ID      SALARY MANAGER_ID

----------- ----------- ----------- ---------- ---------- ------- ----------

199 Douglas     Grant      DGRANT      SH_CLERK     2600        124

下面查看跟踪文件底部的内容,该跟踪文件位于由初始参数USER_DUMP_DEST指定的目录中(在Oracle Database 11g中由DIAGNOSTIC_DEST参数指定):

Trace file

/u01/app/oracle/diag/rdbms/dw/dw/trace/dw_ora_31128.trc

Oracle Database 11g Enterprise Edition

                   Release 11.1.0.6.0 ¨C Productio

With the Partitioning, OLAP, Data Mining and

                   Real Application Testing options

ORACLE_HOME = /u01/app/oracle/product/11.1.0/db_1

System name:    Linux

Node name:      dw

Release:        2.6.9-55.0.2.0.1.EL

Version:        #1 Mon Jun 25 14:24:38 PDT 2007

Machine:        i686

Instance name: dw

Redo thread mounted by this instance: 1

Oracle process number: 40

Unix process pid: 31128, image: oracle@dw (TNS V1-V3)

*** 2007-08-12 12:48:37.852

*** SESSION ID:(120.9389) 2007-08-12 12:48:37.852

*** CLIENT ID:() 2007-08-12 12:48:37.852

*** SERVICE NAME:(SYS$USERS) 2007-08-12 12:48:37.852

*** MODULE NAME:(SQL*Plus) 2007-08-12 12:48:37.852

*** ACTION NAME:() 2007-08-12 12:48:37.852

-------------------------------------------------------------

Logon user     : DGRANT

Table/View     : HR.EMPLOYEES

Policy name    : EMP_SELECT_RESTRICT

Policy function: VPD.GET_PREDICATES.EMP_SELECT_RESTRICT

RLS view :

SELECT  "EMPLOYEE_ID","FIRST_NAME","LAST_NAME",

"EMAIL","PHONE_NUMBER",

"HIRE_DATE","JOB_ID","SALARY","COMMISSION_PCT","MANAGER_ID",

"DEPARTMENT_ID" FROM "HR"."EMPLOYEES"

"EMPLOYEES" WHERE (EMPLOYEE_ID = 199 OR MANAGER_ID = 199)

-------------------------------------------------------------/u01/app/oracle/admin/dw/udump/dw_ora_32530.trc

. . .

*** MODULE NAME:(SQL*Plus) 2004-02-19 20:50:38.132

*** SERVICE NAME:(SYS$USERS) 2004-02-19 20:50:38.132

*** SESSION ID:(265.44) 2004-02-19 20:50:38.132

-------------------------------------------------------------

Logon user          : DGRANT

Table/View          : HR.EMPLOYEES

Policy name        : EMP_SELECT_RESTRICT

Policy function : VPD.GET_PREDICATES.EMP_SELECT_RESTRICT

RLS view :

SELECT "EMPLOYEE_ID","FIRST_NAME","LAST_NAME","EMAIL",

"PHONE_NUMBER","HIRE_DATE","JOB_ID","SALARY","COMMISSION_PCT",

"MANAGER_ID","DEPARTMENT_ID"

FROM "HR"."EMPLOYEES" "EMPLOYEES"

WHERE (EMPLOYEE_ID = 199 OR MANAGER_ID = 199)

用户的初始SQL语句以及附加的谓词都清楚地显示在跟踪文件中。使用这种方法的不利方面在于,虽然用户可能也许能够访问动态性能视图,但开发人员通常可能没有访问对服务器自身上的用户转储目录的访问权。因此,在尝试调整谓词问题时可能需要DBA的参与。

确保在完成调试时关闭跟踪,这样可以减少与跟踪操作关联的系统开销和磁盘空间(否则只能退出系统):

SQL> alter session set events '10730 trace name context off';

Session altered.

109.4  审计

Oracle使用大量不同的审计方法来监控使用何种权限,以及访问哪些对象。审计不会防止使用这些权限,但可以提供有用的信息,用于揭示权限的滥用和误用。

表109-16中总结了Oracle数据库中不同类型的审计。

表109-16  审 计 类 型

审 核计 类 型

说    明

语句审计

按照语句类型审计SQL语句,而不论访问何种特定的模式对象。也可以在数据库中指定一个或多个用户,针对特定的语句审计这些用户

权限审计

审计系统权限,例如CREATE TABLE或ALTER INDEX。和语句审计一样,权限审计可以指定一个或多个特定的用户作为审计的目标

模式对象审计

审计对特定模式对象上运行起作用的特定语句(例如,DEPARTMENTS表上的UPDATE语句)。模式对象审计总是应用于数据库中的所有用户

细粒度的审计

根据访问对象的内容来审计表访问和权限。使用程序包DBMS_FGA来建立特定表上的策略

下面几节中将回顾介绍DBA如何管理系统和对象权限使用的审计。当需要一定的粒度时,DBA可以使用细粒度的审计来监控对表中某些行或列的访问,而不仅仅是是否访问表。

109.4.1  审计位置

审计记录可以发送到SYS.AUD$数据库表或操作系统文件。为了启用审计并指定记录审计记录的位置,将初始参数AUDIT_TRAIL设置为如下4几个值之一中的一个:

参  数  值

动    作

NONE, FALSE

禁用审计

OS

启用审计,将审计记录发送到操作系统文件

DB, TRUE

启用审计,将审计记录发送到SYS.AUD$表

DB_EXTENDED

启用审计,将审计记录发送到SYS.AUD$表,并在CLOB列SQLBIND和SQLTEXT中记录额外的信息

XML

启用审计,以XML格式写所有审计记录

EXTENDED

启用审计,在审计跟踪中记录所有列,包括SqlText和SqlBind的值

参数 AUDIT_TRAIL不是动态的,为了使AUDIT_TRAIL参数中的改动生效,必须关闭数据库并重新启动。在对SYS.AUD$表进行审计时,应该 注意监控该表的大小,以避免影响SYS表空间中其他对象的空间需求。推荐周期性归档SYS.AUD$中的行,并且截取该表。Oracle提供了角色 DELETE_CATALOG_ROLE,和批处理工作作业中的特殊账户一起使用,用于归档和截取审计表。

109.4.2  语句审计

所有类型的审计都使用audit命令来打开审计,并且使用noaudit命令来关闭审计。对于语句审计,audit命令的格形式看起来如下所示:

AUDIT sql_statement_clause BY {SESSION | ACCESS}

     WHENEVER [NOT] SUCCESSFUL;

AUDIT sql_statement_clause BY {SESSION | ACCESS}

sql_statement_clause包含很多条不同的信息大量不同的信息块,例如希望审计的SQL语句类型以及审计什  么人。

此外,希望在每次动作发生时都对其进行审计(by access)或者只审计一次(by session)。默认是by session。

有时希望审计成功的动作:没有生成错误消息的语句。对于这些语句,添加whenever successful。其他一些时候而有时只关心使用审计语句的命令是否失败,失败原因是、这种失败是由于权限违犯、用完表空间中的空间还是或者语法错误。对于这些情况,使用whenever not successful。

对于大多数类别的审计方法,如果确实希望审计所有类型的表访问或某个用户的任何权限,则可以指定all而不是单个的语句类型或对象。

表109-17列出了可以审计的语句类型,并且在每个类别中包含了相关语句的简要描述。如果指定all,则审计该列表中的任何语句。然而,表9-18中的语句类型在启用审计时不属于all类别;必须在audit命令中显式地指定它们。

表109-17  包括在ALL类别中的可审计语句

语 句 选 项

SQL操作

ALTER SYSTEM

所有ALTER SYSTEM选项,例如,动态改变实例参数,切换到下一个日志文件组,以及终止用户会话

CLUSTER

CREATE、ALTER、DROP或TRUNCATE集群

CONTEXT

CREATE CONTEXT或DROP CONTEXT

DATABASE LINK

CREATE或DROP数据库链接

DIMENSION

CREATE、ALTER或DROP维数

DIRECTORY

CREATE或DROP目录

INDEX

CREATE、ALTER或DROP索引

MATERIALIZED VIEW

CREATE、ALTER或DROP物化视图

NOT EXISTS

由于不存在的引用对象而造成的SQL语句的失败

PROCEDURE

CREATE或DROP FUNCTION、LIBRARY、PACKAGE、PACKAGE BODY或PROCEDURE

PROFILE

CREATE、ALTER或DROP配置文件

PUBLIC DATABASE LINK

CREATE或DROP公有数据库链接

PUBLIC SYNONYM

CREATE或DROP公有同义词

ROLE

CREATE、ALTER、DROP或SET角色

ROLLBACK SEGMENT

CREATE、ALTER或DROP回滚段

SEQUENCE

CREATE或DROP序列

SESSION

登录和退出

SYNONYM

CREATE或DROP同义词

SYSTEM AUDIT

系统权限的AUDIT或NOAUDIT

SYSTEM GRANT

GRANT或REVOKE系统权限和角色

TABLE

CREATE、DROP或TRUNCATE表

TABLESPACE

CREATE、ALTER或DROP表空间

TRIGGER

CREATE、ALTER(启用/禁用)、DROP触发器;具有ENABLE ALL TRIGGERS或DISABLE ALL TRIGGERS的ALTER TABLE

TYPE

CREATE、ALTER和DROP类型以及类型主体

USER

CREATE、ALTER或DROP用户

VIEW

CREATE或DROP视图

一些示例可以帮助读者更清楚地了解所有这些选项。在示例数据库中,用户SCOTT具有HR模式和其他模式中表上的所有权限。允许SCOTT创建其中一些表上的索引,但万一有一些与执行计划改动相关的性能问题,则需要知道何时创建这些索引。可以使用如下命令审计SCOTT的索引创建:

SQL> audit index by scott whenever successful;

Audit succeeded.

后面的某一天,SCOTT创建了HR.JOBS表上的索引:

SQL> create index job_title_idx on hr.jobs(job_title);

Index created.

检查数据字典视图DBA_AUDIT_TRAIL中的审计跟踪,可以看到SCOTT实际上在2月24日的9:21 P.M.创建了索引:

SQL> select username, to_char(timestamp,'MM/DD/YY HH24:MI') Timestamp,

2       obj_name, action_name, sql_text from dba_audit_trail

3   where username = 'SCOTT';

 

USERNAME   TIMESTAMP       OBJ_NAME         ACTION_NAME       SQL_TEXT

---------- -------------- ---------------- ---------------- ---------------

SCOTT     02/24/04 21:24 JOB_TITLE_IDX     CREATE INDEX       create index j

ob_title_idx on

hr.jobs(job_ti

tle)

1 row selected.

表109-18  显式指定的语句类型

语 句 选 项

SQL 操 作

ALTER SEQUENCE

任何ALTER SEQUENCE命令

ALTER TABLE

任何ALTER TABLE命令

COMMENT TABLE

添加注释到表、视图、物化视图或它们中的任何列

DELETE TABLE

删除表或视图中的行

EXECUTE PROCEDURE

执行程序包中的过程、函数或任何变量或游标

GRANT DIRECTORY

GRANT或REVOKE DIRECTORY对象表上的权限

GRANT PROCEDURE

GRANT或REVOKE过程、函数或程序包上的权限

GRANT SEQUENCE

GRANT或REVOKE序列上的权限

GRANT TABLE

GRANT或REVOKE表、视图或物化视图上的权限

GRANT TYPE

GRANT或REVOKE TYPE上的权限

INSERT TABLE

INSERT INTO表或视图

LOCK TABLE

表或视图上的LOCK TABLE命令

SELECT SEQUENCE

引用序列的CURRVAL或NEXTVAL的任何命令

SELECT TABLE

SELECT FROM表、视图或物化视图

UPDATE TABLE

在表或视图上执行UPDATE

 

一些示例可以帮助读者更清楚地了解所有这些选项。在示例数据库中,用户KSHELTON具有HR模式和其他模式中所有表上的权限。允许KSHELTON创建其中一些表上的索引,但如果有一些与执行计划改动相关的性能问题,则需要知道何时创建这些索引。可以使用如下命令审计KSHELTON创建的索引:

SQL> audit index by kshelton;

Audit succeeded.

后面的某一天,KSHELTON在HR.JOBS表上创建了一个索引:

SQL> create index job_title_idx on hr.jobs(job_title);

Index created.

检查数据字典视图DBA_AUDIT_TRAIL中的审计跟踪,可以看到KSHELTON实际上在8月12日的5:15 P.M.创建了索引:

SQL> select username, to_char(timestamp,'MM/DD/YY HH24:MI') Timestamp,

  2      obj_name, action_name, sql_text from dba_audit_trail

  3  where username = 'KSHELTON';

USERNAME   TIMESTAMP        OBJ_NAME        ACTION_NAME     SQL_TEXT

--------- -------------- -------------- -------------- ----------------

KSHELTON   08/12/07 17:15 JOB_TITLE_IDX  CREATE INDEX   create index hr.

                                                                    job_title_idx on

                                                                    hr.jobs(job_title)

1 row selected.

注意:

从Oracle Database 11g开始,只有在初始参数AUDIT_TRAIL被设置为DB_EXTENDED时,才填充DBA_AUDIT_TRAIL中的列SQL_TEXT和SQL_BIND。默认情况下,AUDIT_TRAIL的值是DB。

为了关闭HR.JOBS表上KSHELTONSCOTT的审计,可以使用noaudit命令,如下所示:

SQL> noaudit index by kshelton;

Noaudit succeeded.

SQL> noaudit index by scott;

也可能希望按常规方式审计成功的和不成功的注册登录,这需要两个audit命令:

SQL> audit session whenever successful;

Audit succeeded.

SQL> audit session whenever not successful;

Audit succeeded.

SQL> audit session whenever successful;

Audit succeeded.

SQL> audit session whenever not successful;

回顾审计跟踪,可以看到用户RJB在8月10日的失败的注册登录尝试:

SQL> select username, to_char(timestamp,'MM/DD/YY HH24:MI') Timestamp,

  2       obj_name, returncode, action_name, sql_text from dba_audit_trail

  3  where action_name in ('LOGON','LOGOFF')

  4        and username in ('SCOTT','RJB','KSHELTON')

  5  order by timestamp desc;

USERNAME   TIMESTAMP        OBJ_NAME  RETURNCODE ACTION_NAME      SQL_TEXT

--------- -------------- --------- --------- -------------- ----------

KSHELTON   08/12/07 17:04                       0 LOGON

SCOTT      08/12/07 16:10                        0 LOGOFF

RJB          08/12/07 11:35                        0 LOGON

RJB          08/12/07 11:35                        0 LOGON

RJB          08/11/07 22:51                        0 LOGON

RJB          08/11/07 22:51                        0 LOGOFF

RJB          08/11/07 21:55                        0 LOGOFF

RJB          08/11/07 21:40                        0 LOGOFF

RJB          08/10/07 22:52                        0 LOGOFF

RJB          08/10/07 22:52                        0 LOGOFF

RJB          08/10/07 22:52                     1017 LOGON

RJB          08/10/07 12:23                        0 LOGOFF

SCOTT      08/03/07 04:18                        0 LOGOFF

13 rows selected.

SQL> select username, to_char(timestamp,'MM/DD/YY HH24:MI') Timestamp,

2       obj_name, returncode, action_name, sql_text from dba_audit_trail

3   where action_name in ('LOGON','LOGOFF')

4   order by timestamp desc;

 

USERNAME    TIMESTAMP      OBJ_NAME   RETURNCODE ACTION_NAME       SQL_TEXT

---------- -------------- ---------- ---------- ----------------- ----------

DBSNMP      02/24/04 21:55                   0 LOGOFF

SYSMAN      02/24/04 21:54                   0 LOGOFF

RJB         02/24/04 21:52                 1017 LOGON

RJB         02/24/04 21:52                  0 LOGON

DBSNMP      02/24/04 21:52                   0 LOGOFF

SCOTT      02/24/04 21:52                   0 LOGON

DBSNMP      02/24/04 21:51                   0 LOGOFF

RJB         02/24/04 21:51                   0 LOGOFF

SCOTT      02/24/04 21:38                   0 LOGOFF

SCOTT      02/24/04 21:24                   0 LOGOFF

 

RETURNCODE代表ORA错误消息。ORA-1017消息表明输入了不正确的密码。注意,如果仅对登录和退出感兴趣,可以改为使用DBA_AUDIT_SESSION视图。

语句审计也包括启动和关闭操作。虽然可以审计SYS.AUD$表中的命令shutdown immediate,但不可以审计SYS.AUD$中的startup命令,因为必须在可以将行添加到这个表中之前启动数据库。对于这些情况,可以在初始参数AUDIT_FILE_DEST中指定的目录$ORACLE_HOME/rdbms/aduit中查找,查看由系统管理员执行的启动操作的记录(默认情况下,此参数包含$ORACLE_HOME/admin/dw/adump)。下面是使用startup命令启动数据库时创建的文本文件:

Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 ¨C Productio

With the Partitioning, OLAP, Data Mining

                       and Real Application Testing options

ORACLE_HOME = /u01/app/oracle/product/11.1.0/db_1

System name:    Linux

Node name:      dw

Release:        2.6.9-55.0.2.0.1.EL

Version:        #1 Mon Jun 25 14:24:38 PDT 2007

Machine:        i686

Instance name: dw

Redo thread mounted by this instance: 1

Oracle process number: 44

Unix process pid: 28962, image: oracle@dw (TNS V1-V3)

Sun Aug 12 11:57:36 2007

ACTION : 'CONNECT'

DATABASE USER: '/'

PRIVILEGE : SYSDBA

CLIENT USER: oracle

CLIENT TERMINAL: pts/2

STATUS: 0

Audit file /u01/app/oracle/product/10.1.0/rdbms/audit/ora_2788.aud

Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production

With the Partitioning, OLAP and Data Mining options

ORACLE_HOME = /u01/app/oracle/product/10.1.0

System name: Linux

Node name: dw10g

Release: 2.4.21-9.0.1.EL

Version: #1 Mon Feb 9 22:26:52 EST 2004

Machine: i686

Instance name: dw

Redo thread mounted by this instance: 0

Oracle process number: 0

2788

 

Tue Feb 24 17:26:01 2004

ACTION : 'STARTUP'

DATABASE USER: '/'

PRIVILEGE : SYSDBA

CLIENT USER: oracle

CLIENT TERMINAL: Not Available

在该示例中,由主机系统上作为oracle角色连接的用户启动数据库,并且该用户使用操作系统验证连接到实例。下一节将介绍额外的系统管理员审计问题。

109.4.3  权限审计

审计系统权限具有与语句审计相同的基本语法,但审计系统权限是除了在sql_statement_clause(中,而不是在语句)中,指定系统权限。

例如,可能希望将ALTER TABLESPACE权限授予所有的DBA,但希望在发生这种情况时生成审计记录。启用对在这种权限的上启用审计的命令看起来类似于语句审计:

SQL> audit alter tablespace by access whenever successful;

Audit succeeded.

每次成功使用ALTER TABLESPACE权限时,都会将一行内容添加到SYS.AUD$。

使用SYSDBA和SYSOPER权限或者以SYS用户连接到数据库的系统管理员可以利用特殊的审计。为了启用这种额外的审计级别,可以设置初始参数AUDIT_SYS_OPERATIONS为TRUE。这种审计记录发送到与操作系统审计记录相同的位置。因此,这个位置是和操作系统相关的。所有在当使用其中一种权限时执行的所有SQL语句,以及作为用户SYS执行的任何SQL语句,都会发送到操作系统审计位置。

109.4.4  模式对象审计

审计对各种模式对象的访问看起来类似于语句审计和权限审计:

AUDIT schema_object_clause BY {SESSION | ACCESS}

     WHENEVER [NOT] SUCCESSFUL;

AUDIT schema_object_clause BY {SESSION | ACCESS}

schema_object_clause指定对象访问的类型以及访问的对象。可以审计特定对象上1314种不同的操作类型,表109-19中列出了这些操作。

表109-19  对象审计选项

对 象 选 项

说    明

ALTER

改变表、序列或物化视图

AUDIT

审计任何对象上的命令

COMMENT

添加注释到表、视图或物化视图

DELETE

从表、视图或物化视图中删除行

EXECUTE

执行过程、函数或程序包

FLASHBACK

执行表或视图上的闪回操作

GRANT

授予任何类型对象上的权限

INDEX

创建表或物化视图上的索引

INSERT

将行插入表、视图或物化视图中

LOCK

锁定表、视图或物化视图

READ

对执行DIRECTORY对象的内容上的执行读操作

RENAME

重命名表、视图或过程

SELECT

从表、视图、序列或物化视图中选择行

UPDATE

更新表、视图或物化视图

如果希望审计HR.JOBS表上的所有insert和update命令,而不管谁正在进行更新,则每次该动作发生时,都可以使用如下所示的audit命令:

SQL> audit insert, update on hr.jobs by access whenever successful;

Audit successful.

SQL> audit insert, update on hr.jobs by access whenever successful;

用户KSHELTONTAMARA决定向添加两个新行到HR.JOBS表添加两个新行:

SQL> insert into hr.jobs (job_id, job_title, min_salary, max_salary)

  2  values ('IN_CFO','Internet Chief Fun Officer', 7500, 50000);

1 row created.

SQL> insert into hr.jobs (job_id, job_title, min_salary, max_salary)

  2  values ('OE_VLD','Order Entry CC Validation', 5500, 20000);

1 row created.

SQL> insert into hr.jobs (job_id, job_title, min_salary, max_salary)

2 values ('IN_CFO','Internet Chief Fun Officer', 7500, 50000);

1 row created.

 

SQL> insert into hr.jobs (job_id, job_title, min_salary, max_salary)

2 values ('OE_VLD','Order Entry CC Validation', 5500, 20000);

查看DBA_AUDIT_TRAIL视图,可以看到KSHELTONTAMARA会话中的两个insert命令:

USERNAME   TIMESTAMP      OWNER    OBJ_NAME   ACTION_NAME

SQL_TEXT

---------- -------------- -------- ---------- ---------------

---------------------------------------------------------------

KSHELTON   08/12/07 22:54 HR       JOBS       INSERT

insert into hr.jobs (job_id, job_title, min_salary, max_salary)

 values ('IN_CFO','Internet Chief Fun Officer', 7500, 50000);

KSHELTON   08/12/07 22:53 HR       JOBS       INSERT

insert into hr.jobs (job_id, job_title, min_salary, max_salary)

 values ('OE_VLD','Order Entry CC Validation', 5500, 20000);

KSHELTON   08/12/07 22:51                     LOGON

3 rows selected.

USERNAME   TIMESTAMP      OWNER   OBJ_NAME    ACTION_NAME

SQL_TEXT

---------- -------------- -------- ---------- ---------------

---------------------------------------------------------------

TAMARA     02/24/04 22:54 HR       JOBS        INSERT

insert into hr.jobs (job_id, job_title, min_salary, max_salary)

values ('IN_CFO','Internet Chief Fun Officer', 7500, 50000);

TAMARA     02/24/04 22:53 HR       JOBS        INSERT

insert into hr.jobs (job_id, job_title, min_salary, max_salary)

values ('OE_VLD','Order Entry CC Validation', 5500, 20000);

TAMARA     02/24/04 22:51                   LOGON

109.4.5  细粒度的审计

从Oracle9i开始,通过引入细粒度的对象审计,或称为FGA,审计变得更为关注某个方面,并且更为精确。由称为DBMS_FGA的PL/SQL程序包实现FGA。

使用标准的审计,可以轻松发现访问了哪些对象以及由谁访问,但无法知道访问了哪些行或列。细粒度的审计可解决这个问题,它不仅为需要访问的行指定谓词(或where子句),还指定了表中访问的列。通过只在访问某些行和列时审计对表的访问,可以极大地减少审计表条目的数量。

程序包DBMS_FGA具有4个过程:

ADD__POLICY

添加使用谓词和审计列的审计策略

DROP_POLICY

删除审计策略

DISABLE_POLICY

禁用审计策略,但保留与表或视图关联的策略

ENABLE_POLICY

启用策略

用户TAMARA通常每天访问HR.EMPLOYEES表,查找雇员的电子邮件地址。系统管理员怀疑TAMARA正在查看经理们的薪水信息,因此他们建立一个FGA策略,用于审计任何对经理对的SALARY列的任何访问:

begin

    dbms_fga.add_policy(

         object_schema =>   'HR',

         object_name =>     'EMPLOYEES',

         policy_name =>     'SAL_SELECT_AUDIT',

         audit_condition => 'instr(job_id,''_MAN'') > 0',

         audit_column =>    'SALARY'

      );

end;

begin

dbms_fga.add_policy(

object_schema =>       'HR',

object_name =>          'EMPLOYEES',

policy_name =>          'SAL_SELECT_AUDIT',

audit_condition =>  'instr(job_id,''_MAN'') > 0',

audit_column =>       'SALARY'

);

可以使用数据字典视图DBA_FGA_AUDIT_TRAIL访问细粒度审计的审计记录。如果一般需要查看标准的审计行和细粒度的审计行,则数据字典视图DBA_COMMON_AUDIT_TRAIL结合了这两种类型审计类型中的行。

继续看示例,用户TAMARA运行了如下两个SQL查询:

SQL> select employee_id, first_name, last_name, email from hr.employees

  2     where employee_id = 114;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL

----------- ------------------ ---------------------   --------------

        114   Den                   Raphaely                  DRAPHEAL

1 row selected.

SQL> select employee_id, first_name, last_name, salary from hr.employees

  2     where employee_id = 114;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY

----------- ------------------ -----------------------   ----------

        114   Den                   Raphaely                       11000

 

1 row selected.

SQL> select employee_id, first_name, last_name, email from hr.employees

2     where employee_id = 114;

 

EMPLOYEE_ID FIRST_NAME           LAST_NAME                EMAIL

----------- -------------------- ------------------------- --------------

114 Den                 Raphaely                 DRAPHEAL

1 row selected.

 

SQL> select employee_id, first_name, last_name, salary from hr.employees

2     where employee_id = 114;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                   SALARY

----------- -------------------- ------------------------- ----------

114 Den                 Raphaely                     11000

第一个查询访问经理信息,但没有访问SALARY列。第二个查询与第一个查询相同,但是访问了SALARY列,因此触发了FGA策略,从而在审计跟踪中生成了一行:

SQL> select to_char(timestamp,'mm/dd/yy hh24:mi') timestamp,

  2      object_schema, object_name, policy_name, statement_type

  3  from dba_fga_audit_trail

  4  where db_user = 'TAMARA';

TIMESTAMP        OBJECT_SCHEMA OBJECT_NAME    POLICY_NAME      STATEMENT_TYPE

-------------- ------------- ------------- ---------------- --------------

08/12/07 18:07 HR               EMPLOYEES      SAL_SELECT_AUDIT SELECT

1 row selected.

SQL> select to_char(timestamp,'mm/dd/yy hh24:mi') timestamp,

2      object_schema, object_name, policy_name, statement_type

3   from dba_fga_audit_trail

4   where db_user = 'TAMARA';

TIMESTAMP      OBJECT_SCHEMA OBJECT_NAME   POLICY_NAME      STATEMENT_TYPE

-------------- -------------- -------------- ---------------- --------------

02/25/04 00:04 HR            EMPLOYEES     SAL_SELECT_AUDIT SELECT

因为在本章前面的VPD示例中建立了细粒度的访问控制来阻止放置对SALARY列的未授权访问,因此需要加倍检查复查策略函数,确保仍然正确限制约束了SALARY信息。细粒度的审计以及标准审计是确保首先正确建立授权策略的好方法。

109.4.6  与审计相关的数据字典视图

表109-20包含了与审计相关的数据字典视图。

表109-20  与审计相关的数据字典视图

数据字典视图

说    明

AUDIT_ACTIONS

包含审计跟踪动作类型代码的描述,例如INSERT、DROP VIEW、DELETE、LOGON和LOCK

DBA_AUDIT_OBJECT

与数据库中对象相关的审计跟踪记录

DBA_AUDIT_POLICIES

数据库中的细粒度审计策略

DBA_AUDIT_SESSION

与CONNECT和DISCONNECT相关的所有审计跟踪记录

DBA_AUDIT_STATEMENT

与GRANT、REVOKE、AUDIT、NOAUDIT和ALTER SYSTEM命令相关的审计跟踪条目

DBA_AUDIT_TRAIL

包含标准审计跟踪条目。USER_AUDIT_TRAILUSER_TRAIL_AUDIT只包含已连接用户的审计行

DBA_FGA_AUDIT_TRAIL

细粒度审计策略的审计跟踪条目

                                                                     (续表)  

数据字典视图

说    明

DBA_COMMON_AUDIT_TRAIL

将标准的审计行和细粒度的审计行结合在一个视图中

DBA_OBJ_AUDIT_OPTS

对数据库对象生效的审计选项

DBA_PRIV_AUDIT_OPTS

对系统权限生效的审计选项

DBA_STMT_AUDIT_OPTS

对语句生效的审计选项

109.4.7  保护审计跟踪

审计跟踪自身需要受到保护,特别是在非系统用户必须访问表SYS.AUD$时。内置的角色DELETE_ANY_CATALOG是非SYS用户可以访问审计跟踪的一种方法(例如,为了归档和截取审计跟踪,以确保它不会影响到SYS表空间中其他对象的空间需求)。

为了建立对审计跟踪自身上的审计,作为以SYSDBA身份连接到数据库,并运行下面的命令:

SQL> audit all on sys.aud$ by access;

Audit succeeded.

现在,所有针对表SYS.AUD$的动作,包括select、insert、update和delete,都记录在SYS.AUD$自身中。但是,您可能会问,如果某个人删除了标识对表SYS.AUD$访问的审计记录,这时会发生什么?此时将删除表中的行,但接着是然后插入另一行,记录行的删除。因此,总是存在一些针对SYS.AUD$表的(有意的或偶然的)活动的证据。此外,如果将AUDIT_SYS _OPERATIONS设置为True,使用as sysdba、as sysoper或以SYS自身连接的任何会话或者作为SYS自身的连接将记录到操作系统审计位置中,可能甚至Oracle DBA可能都无法访问该位置。因此,有许多合适适当的安全措施,用于确保记录数据库中所有权限的活动,以及隐藏该活动的任何尝试。

9.4.8  启用增强的审计

从Oracle Database 11g开始,数据库配置助手(Database Configuration Assistant,DBCA)很容易启用默认的(增强的)审计。虽然记录审计信息有一些系统开销,但兼容性需求(例如,Sarbanes-Oxley法案中规定的兼容性需求)要求严格监控所有业务操作,包括数据库中与安全相关的操作。

可以在创建数据库时或在数据库已经创建之后使用DBCA配置默认审计。如果已经改变了很多审计设置,并想要将审计选项重置为基线值,则在数据库已创建之后使用DBCA配置默认审计就非常有用。

除将初始参数AUDIT_TRAIL的值设置为DB外,默认审计设置还审计audit role命令本身。另外,在Audited Privileges选项卡的Oracle Enterprise Manager Audit Settings页面中,可以查看默认的审计权限。图9-9展示了默认的审计权限以及本章前面创建的其他两个审计权限。

image059.jpg

图9-9  使用OEM显示审计权限

109.5  数据加密技术

数据加密可以增强数据库内部和外部的安全性。用户可能具有访问表中大多数列的合法需求,但如果对其中一列进行加密,并且用户不知道加密密钥,则无法使用相关的信息。同样的问题相同的概念也适用于需要通过网络安全发送的信息。本章已介绍的技术,包括验证、授权和审计,可以确保数据库用户合法访问数据,但不能阻止操作系统用户访问数据,因为这些用户可能具有操作系统文件的访问权,而数据库本身就是由这些操作系统文件组成的。

用户可以采用如下两种方法进行数据加密:一种方法是使用程序包DBMS_CRYPTO(在Oracle Database 10g中,这一程序包替换了Oracle9i中的DBMS_OBFUSCATION_TOOLKIT程序包);另一种方法是透明数据加密,这种方法以全局方式存储加密密钥,并包含加密整个表空间的方法。

9.5.1  DBMS_CRYPTO程序包

作为Oracle 10g的新增内容,程序包DBMS_CRYPTO代替了DBMS_OBFUSCATION_ TOOLKIT,并且包括Advanced Encryption Standard(AES)加密算法,(AES算法它代替了Data Encryption Standard(DES)算法)。

DBMS_CRYPTO中的过程可以生成私有密钥,也可以自己指定并存储密钥。与只可以加密RAW或VARCHAR2数据类型的DBMS_OBFUSCATION_TOOLKIT不同的是,DBMS_ CRYPTO可以加密BLOB和CLOB类型。

9.5.2  透明数据加密

透明数据加密是一种基于密钥的访问控制系统,它依赖于外部模块实施授权。包含加密列的每个表都有自己的加密密钥,加密密钥又由为数据库创建的主密钥来加密,加密密钥以加密方式存储在数据库中,但主密钥并不存储在数据库中。重点要强调的是“透明”这一术语——当访问表中或加密表空间中的加密列时,授权用户不必指定密码或密钥。

●       虽然Oracle Database 11g大大地增强了透明数据加密特性,但它的使用仍然受到一些限制,例如,不能使用外键约束对列进行加密,因为每个表都有一个唯一的列加密密钥。一般来说,这不应该是什么问题,因为外键约束中使用的密钥应该是系统生成的、唯一的和非智能的。表的业务键和其他业务属性可能更需要加密,且它们通常并不参与与其他表的外键关系。其他数据库特性和类型也不适合进行透明数据加密:

●       除B-树索引外的其他索引类型

●       索引的范围扫描搜索

●       BFILE(外部对象)

●       物化视图日志

●       同步的更改数据捕获(Synchronous Change Data Capture)

●       可移植的表空间

●       原来的导入/导出实用工具(Oracle 9i及更早版本)

另外还可以选择使用DBMS_CRYPTO以手动方式加密这些类型和特性。

注意:

在Oracle Database 11g中,现在可以加密内部大对象,例如BLOB和CLOB类型。

1. 创建Oracle钱夹

使用Oracle企业管理器可以为透明数据加密创建一个钱夹。选择Server选项卡,然后单击Security Heading下面的Transparent Data Encryption链接,将会看到如图9-10所示的页面。在此例中,还没有创建钱夹。文件sqlnet.ora用ENCRYPTION_WALLET_LOCATION变量存储钱夹的位置。如果sqlnet.ora文件中不存在此变量,则将钱夹创建在$ORACLE_HOME/admin/ database_name/wallet中,在此例中是/u01/app/oracle/admin/dw/wallet。

image060.jpg

图9-10  透明数据加密:创建一个钱夹

要创建加密密钥,并将它放在钱夹中,需要创建一个钱夹密码,此密码至少有10个字符,要包含大写字母、小写字母、数字和标点符号。单击OK,创建钱夹,可以看到如图9-11所示的页面。

image061.jpg

图9-11  透明数据加密:钱夹处于打开状态

如果主密钥被泄密,则可以使用图9-10中的页面重新创建主密钥。也可以关闭钱夹——禁用透明数据加密(Transparent Data Encryption)——并阻止访问任何加密的表列或表空间。

创建、打开和关闭钱夹的等价SQL命令非常简单,且输入这些命令所花费的时间可能比使用Oracle企业管理器要少!要创建新的密钥,并在钱夹还不存在时创建钱夹,则使用alter system命令,如下所示:

SQL> alter system set encryption key identified by "Uni123#Lng";

System altered.

SQL>

注意将钱夹密钥放在双引号中,这一点非常重要。如果不将钱夹密钥用双引号引起来,则密码将映射所有小写字母,钱夹将不处于打开状态。数据库实例被停机并重新启动之后,如果此任务未以其他方式自动化,则需要使用alter system命令打开钱夹:

SQL> alter system set encryption wallet open identified by "Uni123#Lng";

System altered.

SQL>

最后,通过关闭钱夹,随时可以毫不费力地禁用对数据库中所有加密列的访问:

SQL> alter system set encryption wallet close;

System altered.

SQL>

要频繁地备份钱夹,且不要忘记钱夹密钥(或者是安全管理员不应该忘记钱夹密钥,安全管理员可以是与DBA不同的角色),因为丢失钱夹或钱夹密码将无法对任何加密的列或表空间进行解密。

2. 加密表

可以加密一个或多个表的一列或多列,具体做法是,在create table命令中的列的数据类型后面添加encrypt关键字;或者是在已存在列的列名后面添加encrypt关键字。例如,要加密EMPLOYEES表的SALARY列,则使用如下命令:

SQL> alter table employees modify (salary encrypt);

Table altered.

SQL>

以前有权访问SALARY列的任何用户仍具有对此列的相同访问权,对用户来说,这完全是透明的。唯一的区别在于,访问包含EMPLOYEES表的操作系统文件的任何人都无法破译SALARY列。

3. 加密表空间

要加密整个数据库,则必须将COMPATIBLE初始化参数设置为11.1.0.0.0,这是Oracle Database 11g的默认设置。如果数据库已从以前的版本升级,且将COMPATIBLE参数改变为11.1.0.0.0,则这种改变是不可逆的。

已存在的表空间不能加密,要加密已有表空间的内容,则必须用ENCRYPTION选项创建一个新的表空间,并将已有的对象复制或移动到新的表空间。Oracle企业管理器可以很容易地创建一个新的加密表空间。在图9-12中,创建一个新的名为USERS_CRYPT的表空间,其大小是500MB,位于ASM磁盘组中。

image062.jpg

图9-12  创建加密的表空间

单击Encryption Options按钮,可以看到以前创建的钱夹的状态(钱夹必须处于打开状态才能创建加密的表空间),可以为表空间选择想要使用的加密算法。单击Continue按钮之后,如图9-13所示,返回到Create Tablespace页面。

单击Show SQL按钮,可以看到Oracle企业管理器创建表空间将使用的SQL命令:

CREATE SMALLFILE TABLESPACE "USERS_CRYPT"

DATAFILE'+DATA' SIZE 500M LOGGING EXTENT MANAGEMENT LOCAL

SEGMENT SPACE MANAGEMENT AUTO NOCOMPRESS ENCRYPTION

USING 'AES256' DEFAULT STORAGE(ENCRYPT)

单击Return按钮,然后单击OK按钮,则Oracle企业管理器创建表空间。

image063.jpg

图9-13  指定加密的表空间选项

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/673037/viewspace-592276/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/673037/viewspace-592276/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值