文章
![]() |
数据库安全工程:分阶段为数据库基础架构构建安全屏障作者:Arup Nanda 出版时间:2006 年 5 月 - 参阅目录和安全性入门指南 |
|||||||||||||||||||||||
第 4 阶段时间: 一个季度您终于走到最后阶段了,这一阶段在四个阶段中也是最长的。 在这一阶段您我们要完成某些更加复杂的设置,并做长期规划以消除潜在威胁。 这一部分内容包括: 您可能已经注意到,本文到现在还没有涉及到作为审计机制的触发器。为什么? 因为使用触发器,就意味着 再次连续地执行 SQL,这增加了整个执行时间。 对生产系统来说,该开销几乎是不可以接受的。 因为细粒度审计 (FGA) 有最小的性能开销,所以在这里它是一个优秀的解决方案。 如果您已经熟悉 FGA,请跳过这一部分,直接阅读策略部分。 Oracle9i 数据库中引入了 FGA 特性,当用户对表进行选择和更改操作时,它将记录一个审计线索。 因这一特性是唯一可记录选择活动的方法,所以它具有里程碑式的意义。 SELECT 语句上的常规审计功能仅仅记录 谁 针对对象发出了语句,但是不记录发送了 什么 语句。 除开详细信息(例如用户名、终端,以及查询时间)之外,FGA 还记录执行过的 SQL 语句和时间实例的 SCN 数量。 当您使用闪回查询重建数据之后,你不仅看到用户提交的语句,还有用户得到结果值。 在 Oracle 数据库 10g 第 1 版对该功能进行了扩展,涵盖其它 DML 语句,例如 插入、 更新,以及 删除。 下面提供了一个小示例: 假设模式 BANK 有一个 ACCOUNTS 表。 Name Null?类型 ---------------- -------- ------------ ACC_NO NOT NULL NUMBER CUST_ID NOT NULL NUMBER BALANCE NUMBER(15,2)为了对其进行审计,您将需要使用提供的程序包 DBMS_FGA 定义相关 FGA 策略。
begin
dbms_fga.add_policy (
object_schema=>'BANK',
object_name => 'EMP',
policy_name => 'ACCOUNTS_ACCESS',
);
end;
以上代码执行完毕之后,将在 ACCOUNTS 表启用 FGA。 也就是说,没有必要对任何初始化参数进行更改,或对该数据库进行回弹。 执行以上代码时,它们在该表上使用共享锁定,因此您可以在线执行。 现在,如果一个名为 ARUP 的用户提交以下语句,对该表中进行选择操作: select * from bank.accounts; 该行动立即记录在称为 FGA Audit Trail的审计追踪中。 您可以使用以下语句对其进行检查: select timestamp, db_user, os_user, object_schema, object_name, sql_text from dba_fga_audit_trail; TIMESTAMP DB_USER OS_USER OBJECT_ OBJECT_N SQL_TEXT --------- ------- ------- ------- -------- --------------------------- 08-FEB-06 ARUP arup BANK ACCOUNTS select * from bank.accounts 该视图也显示许多其它列。 您可以使用多种方法对 FGA 进行配置。 例如,如果您希望记录用户选择 BALANCE 列且余额超过 20,000 时的操作,你可以另外添加一些参数,同时定义 FGA 策略如下:
begin
dbms_fga.add_policy (
object_schema =>'BANK',
object_name => 'EMP',
policy_name => 'ACCOUNTS_ACCESS',
audit_column => 'BALANCE',
audit_condition => 'BALANCE >= 20000'
);
end;
FGA 的另一个特性就是当条件满足时,FGA 还能在审计线索中进行记录之外调用存储过程。 在有额外处理(例如发送电子邮件)的情形,这一特性的效果极其显著。 这样的 SP 被称为 FGA 策略的处理模块。 请记住,选择语句可以激活 FGA,也可以激活这些处理器模块。 在某种意义上说,这使处理器模块“选择触发器”语句。 Oracle 数据库 10g 也介绍更多的 FGA 增强特性,例如这两个值得关注的特性: 绑定变量。 使用 FGA,您可以通过在 DBMS_FGA.ADD_POLICY 过程中使用参数来捕获语句中的绑定变量。 audit_trail => DB_EXTENDED 然后您可以将它们放到数据库初始化文件中,这样 FGA 可以一直对它进行记录。 相关列。 请看以下两个语句: select balance from accounts where account_no = 9995; select sum(balance) from accounts; 很明显,第一条语句请求了 具体的敏感信息(基于此信息可识别客户),您可能想编辑该信息。 第二条语句危险系数较低,用户使用该语句找不到关于该客户的任何具体的敏感数据。 按照您的安全策略,您可能希望记录第一条语句,不记录第二条语句。 这样有助于限制该线索的大小。 要完成这一任务,您可以使用另外一个参数 audit_column_opts => DBMS_FGA.ALL_COLUMNS,同时定义策略如下:
begin
dbms_fga.add_policy (
object_schema => 'ANANDA',
object_name => 'EMP',
policy_name => 'ACCOUNTS_ACCESS',
audit_column => 'BALANCE',
audit_condition => 'BALANCE >= 20000'
statement_types => 'SELECT');
audit_column_opts => DBMS_FGA.ALL_COLUMNS
);
end;
默认情况下为 DBMS_FGA.ANY_COLUMNS,无论 哪个 列被选择,它都能触发审计线索。 到这里我们只是精浅地涉及了 FGA。 要对 FGA 有一个全面的了解,获取更多的的示例,请参阅我的系列文章“对实际问题进行细粒度审计。”,分为三章。 " 同时我在 Oracle PL/SQL for DBAs (2005, O'Reilly Media) 一书中也对此也进行详细的讨论。 策略 和常规审计相比,FGA 的最大优点是它不需要任何特定的初始化参数,所有它不需要数据库回弹。 您可以按需在对象上启用或禁用 FGA 策略。 您需要查找具体的敏感列和且有选择地查找这些列中的敏感值。 首先,您需要制定审计策略。 下面是一个典型的策略示例: 在 SALARIES 表中:
把该策略记住后,您应该创建两个不同的 FGA 策略。 首先,针对 EMPNO >= 1000、SALARY 列和 BONUS 列的通用策略。
begin
dbms_fga.add_policy (
object_schema => 'ACCMAN',
object_name => 'EMP',
policy_name => 'EMP_SEL_POL',
audit_column => 'SALARY, BONUS',
statement_types => 'SELECT');
audit_option => 'EMPNO >= 1000 and USER NOT IN(''SAP_PAYROLL_APP'', ''MONICA'', ''ADAM'')',
handler_module => 'ENQUEUE_MESSAGE'
);
end;
然后,针对 EMPNO < 1,000 创建用于全部列的策略。
begin
dbms_fga.add_policy (
object_schema => 'ACCMAN',
object_name => 'EMP',
policy_name => 'EMP_SEL_POL',
statement_types => 'SELECT');
audit_option => 'EMPNO < 1000',
handler_module => 'ENQUEUE_MESSAGE'
);
end;
第三,给 MONICA 和 ADAM 添加特殊的策略。
begin
dbms_fga.add_policy (
object_schema => 'ACCMAN',
object_name => 'EMP',
policy_name => 'EMP_SEL_POL',
audit_column => 'SALARY, BONUS',
statement_types => 'SELECT');
audit_option => 'EMPNO >= 1000 AND SAL <= 1000 and USER IN
(''MONICA'', ''ADAM'') AND USER != ''SAP_PAYROLL_APP''',
handler_module => 'ENQUEUE_MESSAGE'
);
end;
正如您所看到的, audit_option 中的条件之间是相互排斥的,所以当用户尝试执行 SELECT 语句时,只有一个策略是有效的,也只有一条记录会被写入。 您可以使用该策略构建 FGA 策略集。 然后,您可以根据需要自由地启用或禁止策略,这不会影响操作。 问题
操作清单
背景 虚拟专用数据库 (VPD) 是一个很大的主题,因此我在这里只将一些基本的。 假设您有一个称为 ACCOUNTS 的表,表中有以下数据:
SQL> select * from rates;
ACCNO ACC_NAME ACC_BAL
---------- -------------------- ----------
1 John 1000
2 Jill 1500
3 Joe 1200
4 Jack 1300
您想确保只有得到适当授权的人才可以查阅授权范围的帐户余额。也就是说,级别 1 看到的余额应该小于 1,000,级别 2 看到的余额应该小于 1,200,级别 3 可以看到所有的余额。 您还有另一张显示用户和级别的表。 SQL> select * from tab; USERNAME USERLEVEL ------------------------------ ---------- CLERK1 1 CLERK2 2 CLERK3 3 要存储用户首次登录时的用户级别,因此需要创建应用程序环境: create context user_level_ctx using set_user_level_ctx; 以及相关的可信过程:
create or replace procedure set_user_level_ctx
(
p_level in number
)
as
begin
dbms_session.set_context (
'USER_LEVEL_CTX',
'LEVEL',
p_level
);
end;
接着,您需要创建登录触发器以设置适当的应用程序环境。
create or replace trigger tr_set_user_level
after logon
on database
declare
l_level number;
begin
select userlevel
into l_level
from arup.userlevels
where username = user;
set_user_level_ctx (l_level);
exception
when NO_DATA_FOUND then
null;
when OTHERS then
raise;
end;
这设置了一个阶段,您可以按照该阶段在应用程序环境属性设置用户级别。 我们测试一下,以确保:
SQL> conn clerk1/clerk1
Connected.
SQL> select sys_context('USER_LEVEL_CTX','LEVEL') from dual;
SYS_CONTEXT('USER_LEVEL_CTX','LEVEL')
--------------------------------------
1
SQL> conn clerk2/clerk2
Connected.
SQL> select sys_context('USER_LEVEL_CTX','LEVEL') from dual;
SYS_CONTEXT('USER_LEVEL_CTX','LEVEL')
--------------------------------------
2
SQL> conn clerk3/clerk3
Connected.
SQL> select sys_context('USER_LEVEL_CTX','LEVEL') from dual;
SYS_CONTEXT('USER_LEVEL_CTX','LEVEL')
--------------------------------------
3
正如您可以看到的,每个用户 ID 都设置了相应的级别。 现在,您可以在表上构建 VPD。 您可以使用所提供的 PL/SQL 包 DBMS_RLS 控制整个 VPD 基础架构;一个称为策略的概念控制着决定应该显示哪些行的规则。 策略将“谓词”(WHERE 条件)应用到表中的所有查询上,有效地限制了对行的访问。 一个称为策略函数的函数生成 WHERE 条件。 因此,首先我们必须创建策略函数,该函数返回 WHERE 条件以将该条件应用到查询中。
create or replace function get_acc_max_bal
(
p_schema in varchar2,
p_obj in varchar2
)
return varchar2
as
l_ret varchar2(2000);
begin
select
case userlevel
when 1 then 'acc_bal <= 1000'
when 2 then 'acc_bal <= 1200'
when 3 then null
else
'1=2'
end
into l_ret
from userlevels
where username = 'HR'
return l_ret;
end;
然后添加策略:
begin
dbms_rls.add_policy (
object_name => 'EMP',
policy_name => 'ACCOUNTS_ACCESS',
policy_function => 'USER_ONLY',
statement_types => 'INSERT, UPDATE, DELETE, SELECT',
update_check => TRUE
);
end;
这次表得到保护。 当 CLERK1 登录并从表中进行选择:
SQL> select * from arup.accounts;
ACCNO ACC_NAME ACC_BAL
---------- -------------------- ----------
1 John 1000
Clerk1 只能看到 ACCNO 1,余额为 1,000。因为没有授予 Clerk1 查看高于 1,000 的账户余额,所以他看不到其它账户。 但是,当 Clerk2 登录时:
SQL> conn clerk2/clerk2
Connected.
SQL> select * from arup.accounts;
ACCNO ACC_NAME ACC_BAL
---------- -------------------- ----------
1 John 1000
2 Joe 1200
她也可以看到 ACCNO 2。 ACCNO 2 的余额为 1,200,在给 Clerk2 的授权限制之内。 您可以使用该技术将被限制的视图类放到表中。 在项目锁定中,这将是一个很方便的工具。 策略 即使 VPD 是很效的,如果您想让一些用户可以不受限制就可以访问表怎么办? 角色 EXEMPT ACCESS POLICY 的确是这样做的。 grant exempt access policy to ananda; 从此处开始,ANANDA 将跳过在所有表中定义的所有访问策略。 使用户跳过所有访问限制可能是不可接受的,然而,一个更好的解决方案是在策略函数中对其进行编码。 一个很好的示例就是表的模式所有者——无疑您想该所有者看到表的所有行而不受到限制。 您可以在策略函数中对其进行如下编码:
create or replace function get_acc_max_bal
(
p_schema in varchar2,
p_obj in varchar2
)
return varchar2
as
l_ret varchar2(2000);
begin
if (p_schema = USER) then
l_ret := NULL;
else
select
case userlevel
when 1 then 'acc_bal <= 1000'
when 2 then 'acc_bal <= 1200'
when 3 then null
else
'1=2'
end
into l_ret
from userlevels
where username = 'HR'
end if;
return l_ret;
end;
当表的所有者登录 (p_schema = USER) 时,该版本函数返回 NULL,所以对表的访问不受限制。 当然,您可以在该函数中进行任意更改,以允许更多用户跳过 VPD 策略。 VPD 的最大挑战是对子表进行限制。 您的限制条件可能在称为 ACC_BAL 的列上;但是所有其它子表不可能有该列。 因此,您如何限制那些表? 例如,这里有一个称为地址的表,该表包含这些客户的地址。 该表没有称为 ACC_BAL 的列,因此您如何对该表设置和 ACCOUNTS 表一样的限制? 有如下两种方式:
您必须按照自己所处的环境从这两种方法中选取一种。 提示
操作计划 这个计划是很复杂的,也是可改变的:
背景 正如您可以看到的,带有明显名字的敏感列是至关重要的安全问题。 策略如果对手以前不了解您数据库的内容,并且这些列的名字不直观,他们将不会去解读列的含义。 这个策略称为“无名安全”。 即使故意闯进数据库的经验丰富的黑客在做其它事情之前仍将需要追捕到列的名称。 因为他们的时间可能有限——几乎一直都是这样——他们通常会转到下一个机会上。 当然,使用无名列也加大了开发的难度。 进行折衷还有其它的办法,然而: 通过 列屏蔽,您可以隐藏列的内容,只有合法用户才可以看到列的内容。 列屏蔽的方法有两种: 使用视图和使用 VPD。 使用视图。 这种方法适用于 Oracle 任何版本,但是如果您的数据库版本是 Oracle9i 或者更早,就只能选择这种方法。 假设您的表和以下类似: SQL> desc patient_diagnosis Name Null?类型 ------------------- ------ ------------- PATIENT_ID NUMBER DIAGNOSIS_ID NUMBER DIAGNOSIS_CODE VARCHAR2(2) DOCTOR_ID NUMBER(2) BILLING_CODE NUMBER(10)行类和以下类似:
SQL> select * from patient_diagnosis;
PATIENT_ID DIAGNOSIS_ID DI DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
1 1 01 1 1003
1 2 02 1 1003
1 3 11 1 1003
2 1 11 1 1005
2 2 41 2 1005
在这里,您想屏蔽列 DIAGNOSIS_CODE 的值。 create view vw_patient_disgnosis as select patient_id, diagnosis_id, doctor_id, billing_code from patient_diagnosis / 然后,您可以给视图 VW_PATIENT_DIAGNOSIS 创建同义词 PATIENT_DIAGNOSIS,授予视图(而不是表)选择。 该视图屏蔽列 DIAGNOSIS_CODE。 这是一个相当简单的解决方案,因此您不要将所有用户的列屏蔽掉,您可能想创建基于角色的匿名——如果用户是一名经理,请显示被保护的列;否则的话不要显示。其方法是:传递应用程序环境或者全球变量以指定用户的角色。 如果应用程序环境属性是 IS_MANAGER,您可以使用:
create or replace view vw_patient_disgnosis
as
select
patient_id,
diagnosis_id,
decode(
sys_context('USER_ROLE_CTX','IS_MANAGER'),
'Y', DIAGNOSIS_CODE, null
) diagnosis_code,
doctor_id,
billing_code
from patient_diagnosis;
这是一个更加灵活的视图,该视图可以授权给所有的用户,该视图的内容会随着用户角色的不同而不同。 使用 VPD。 Oracle 数据库 10g 中引入的新特性使 VPD 更加有用: 创建视图是没有必要的。 相反,VPD 策略可能抑制显示。 这里,VPD 策略函数和以下类似: 1 create or replace function pd_pol 2 ( 3 p_schema in varchar2, 4 p_obj in varchar2 5 ) 6 return varchar2 7 is 8 l_ret varchar2(2000); 9 begin 10 if (p_schema = USER) then 11 l_ret := NULL; 12 else 13 l_ret := '1=2'; 14 end if; 15 return l_ret; 16 end;现在构建策略函数: 1 begin 2 dbms_rls.add_policy ( 3 object_schema => 'ARUP', 4 object_name => 'PATIENT_DIAGNOSIS', 5 policy_name => 'PD_POL', 6 policy_function => 'PD_POL', 7 statement_types => 'SELECT', 8 update_check => TRUE, 9 sec_relevant_cols => 'DIAGNOSIS_CODE', 10 sec_relevant_cols_opt => dbms_rls.all_rows 11 ); 12 end; 注意行号 9 和 10。在第 9 行中,我们提及将列 DIAGNOSIS_CODE 作为敏感列。 在第 10 行中,我们指出如果选择了该列,VPD 显示所有列;但是该列值却显示为 NULL。 这就有效地屏蔽了该列。 在策略函数中,请注意如果表的所有者进行选择,应用的谓词为 NULL。因此,VPD 限制就不被应用,列也不显示。 请记住,没有“更换”策略的方法。 如果旧策略还存在,您必须首先抛弃旧策略。
begin
dbms_rls.drop_policy (
object_schema => 'ARUP',
object_name => 'PATIENT_DIAGNOSIS',
policy_name => 'PD_POL'
);
end;
现在,您可以进行测试。
SQL> conn arup/arup
Connected.
SQL> select * from patient_diagnosis;
PATIENT_ID DIAGNOSIS_ID DI DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
1 1 01 1 1003
1 2 02 1 1003
1 3 11 1 1003
2 1 11 1 1005
2 2 41 2 1005
注意:DIAGNOSIS_CODE 列值显示出来了,因为 ARUP 是表的所有者,ARUP 应该看得到这些值。 现在,以对该表有选择权限的另一名用户身份进行连接,执行相同的查询。
SQL> set null ?
SQL> conn ananda/ananda
SQL> select * from arup.patient_diagnosis;
PATIENT_ID DIAGNOSIS_ID D DOCTOR_ID BILLING_CODE
---------- ------------ - ---------- ------------
1 1 ? 1 1003
1 2 ? 1 1003
1 3 ? 1 1003
2 1 ? 1 1005
2 2 ? 2 1005
注意列 DIAGNOSIS_CODE 是如何显示所有空值的。 除了不需要在表上创建视图,不需要创建同义词指向该视图,不需要维护额外的授权之外,该方法是更加优秀的。 如果您需要拥有不同的策略把该值显示给不同的人,您可以很容易地修改策略函数(第 11 行)添加更多的检查。 例如,您的策略可以是:所有用户都可以看到敏感性不强的诊断代码(例如普通感冒)。 因此,您的策略函数和下面的类似,假设一般性感冒的 DIAGNOSIS_CODE 为“01”。 1 create or replace function pd_pol 2 ( 3 p_schema in varchar2, 4 p_obj in varchar2 5 ) 6 return varchar2 7 is 8 l_ret varchar2(2000); 9 begin 10 if (p_schema = USER) then 11 l_ret := NULL; 12 else 13 l_ret := 'diagnosis_code=''01'''; 14 end if; 15 return l_ret; 16* end; 注意:仅当诊断代码为“01”而不是其它时,我们在第 13 行添加要显示的额外谓词。 现在进行测试。
SQL> conn arup/arup
Connected.
SQL> select * from arup.patient_diagnosis;
PATIENT_ID DIAGNOSIS_ID DI DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
1 1 01 1 1003
1 2 02 1 1003
1 3 11 1 1003
2 1 11 1 1005
2 2 41 2 1005
SQL> conn ananda/ananda
Connected.
SQL> select * from arup.patient_diagnosis;
PATIENT_ID DIAGNOSIS_ID DI DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
1 1 01 1 1003
1 2 ? 1 1003
1 3 ? 1 1003
2 1 ? 1 1005
2 2 ? 2 1005
注意:诊断代码“01”代表病人 id 1 和诊断 id 1,这是 唯一允许的诊断代码;因此显示得很清晰。 其它的显示已经显示为孔,并且得到有效地屏蔽。 提示 如果您使用视图方法(这里敏感列只是从该视图中删除),则将会引发一个问题,这里程序使用像 SELECT * FROM TABLE ... 一样的结构。 因为已经没有明确对列进行命名,缺少一列将影响到程序执行。 但是,这不是一个关于修改视图方法(在这里列仍然存在但是为空)的问题。 有一个您应该意识到的很重要的提示。 假如您有一个称为“CONTRACT_AMOUNT”的列;如果数值小于某个特定值(比如 500),该列就显示。如果数值大于 500,该列就显示为空。 该表有三行,这三行所在列的数值分别为 300, 300, 600。 在列屏蔽之前,如果用户提交以下查询 select avg (contract_amount) from contracts; 他将得到 400 (就是 300,300 和 600 的平均值)。 在列屏蔽之后,数值为 $600 的列的值将变为空,因此用户将看到的值分别为 300,300 和空。 现在,输入同样的查询,将会显示 200 (300,300 和空)。 请注意一个重要的区别: 所显示的值为 200; 而不是 400。 请意识到列屏蔽可能引入的这种重要区别。 操作计划
4.4 对敏感的数据进行加密 背景 请记住,加密不能替代其它层次的安全性。 不管怎样,您必须有那些防御。 而且,加密是一个很大的课题,但是我将在这里给您一个可引发操作的概述。 Oracle 提供两种加密方式:
我建议在您阅读策略部分之前,请分别察看 Oracle 文档(Oracle 数据库安全指南的第 17 章 和 Oracle 数据库高级安全管理员指南的第 3 章)。 策略选择常规加密,还是透明的数据加密是很重要的。 (然而,在 Oracle 数据库 10g 第 2 版之前, 您只能选择常规加密。)
如果您决定使用 TDE,请采取以下步骤:
之后,您创建的表可以包含经过加密的列: create table accounts ( acc_no number not null, first_name varchar2(30) not null, last_name varchar2(30) not null, SSN varchar2(9) ENCRYPT USING 'AES128', acc_type varchar2(1) not null, folio_id number ENCRYPT USING 'AES128', sub_acc_type varchar2(30), acc_open_dt date not null, acc_mod_dt date, acc_mgr_id number ) 当用户将数据插进该表时,数据就自动转化为加密的数据并放置到磁盘上。 类似地,当选择语句检索到数据时,数据自动转化为加密的值,并且向用户显示。 提示
操作计划
4.5 安全备份 背景 幸运地是,即使这样您只要使用加密备份还是可以消除这种风险的。 策略 透明模式。 按照这种方法(也是最常用的方法),RMAN 从加密钱夹中获取加密密码(在前面讨论过了),并使用它对备份集进行加密。 不必说,在备份和恢复中钱夹必须是打开的。 如果钱夹没有打开,您将看到以下错误: ORA-19914: unable to encrypt backup ORA-28365: wallet is not open
基于密码的模式。 这种情况下,不需要将钱夹用于密码管理。 密码加密备份,同时密码本身也使用密码加密。 命令如下:
RMAN> set encryption on identified by "53cr3t" only;
RMAN> backup tablespace users;
密码将对上面产生的备份集进行加密。 为了在恢复中对密码进行加密,您必须使用如下密码:
RMAN> set decryption identified by "53cr3t ";
RMAN> restore tablespace users;
这种方法就不需要使用钱夹了。 因此在任何服务器上恢复备份,您只需要密码,不再需要钱夹。 然而,您的密码在脚本中必须是可见的。这样,任何能访问数据库服务器的恶意入侵者将能够读取该密码。 请参阅第 2 阶段,其中涉及了如何隐藏密码的内容。 混合模式。由名称可知,该模式两种方法的结合体。 您按照以下方式进行备份:
RMAN> set encryption on identified by "53cr3t";
RMAN> backup tablespace users;
注意:在命令 set encryption 中没有“only”语句。 这样就可以使用两种方法之一来恢复备份: 使用密码“tiger”,或者打开钱包。 例如,请注意以下命令。 没有提供密码,但是成功地进行了恢复。 RMAN> sql 'alter tablespace users offline'; RMAN> restore tablespace users; Starting restore at 26-MAY-05 allocated channel:ORA_DISK_1 ... restore command output comes here ... 当您使用脚本处理备份时,经常不得不将数据库恢复到不同的服务器(例如 QA 服务器)上时,这种方法将派上大用场。 但是一般来说,这种方法通常没有太大的实际用处。 如果您使用透明模式进行备份加密,您也可以备份钱夹。 即使对手获得了钱夹,他没有密码也打不开钱夹。 问题
操作计划
背景 数据库安全实施的一个很重要的方面是确保数据库上不发生未授权的 DDL 活动。恶意入侵者获取连接数据库的合法路由后,可以很方便的写几段代码来对数据库实施简单的拒绝服务攻击。 在第 3 阶段中,您了解了如何保护主要对象,所以没有 DBA 的同意是不能更改主要对象的。 但是,如果非法更改得到同意,但在后来才得知发生了攻击,该怎么办呢? 这就要用到安全的第四个方面——责任可查性。 一个选项是开启 DDL 审计以跟踪 DDL 活动。 总而言之,这是最容易的方法——易于设置,更易于浏览,可以进行归档,等等。 然而,审计会影响性能,这是我们正试图避免的。 问题是如何重新跟踪 DDL 语句,而不用对审计进行设置。 策略 下文告诉您如何设置日志挖掘以挖掘 DDL 详细信息。 首先,获取要挖掘的在线日志文件或者归档日志文件,并将它们添加到 Log Miner 会话中。
sqlplus / as sysdba
begin
dbms_logmnr.add_logfile (
'C:\ORACLE\DATABASE\ANANDA\REDO03.LOG');
dbms_logmnr.add_logfile (
'C:\ORACLE\DATABASE\ANANDA\REDO02.LOG');
dbms_logmnr.add_logfile (
'C:\ORACLE\DATABASE\ANANDA\REDO01.LOG');
end;
/
添加文件之后,启动 Log Miner 会话。 您必须传递数据字典源;在这里我们已经将在线类别指定为源。
begin
dbms_logmnr.start_logmnr (
options => dbms_logmnr.dict_from_online_catalog
);
end;
被挖掘的内容放在称为 V$LOGMNR_CONTENTS 的视图中;但是该视图是临时的——仅仅启动 Log Miner 的会话可以看到该视图。 因此,如果以后您想进行分析,您需要将它保存在永久表中。 create table lm_contents nologging as select * from v$logmnr_contents;Now for the analysis. To find the DDL commands you would issue the following query:
select sql_redo
from lm_contents
where operation = 'DDL'
and seg_owner not in ('SYS','SYSTEM','PUBLIC');
下面是一个样例输出: 注意:没有 DROP TABLE 语句——在 Oracle 数据库 10g中,删除的表实际上没有被删除,而是进行了重新命名。 SQL_REDO 将反映这点。 实际上,用户使用 PURGE 子句删除表时,列 SQL_REDO 将会反映正确的命令。 为了保存空间,我已经修剪了输出,所以函数和过程的 DDL 出现了一部分。 我也已经使用 RECSEPCHAR '.'以显示多行记录中的设计行。)
SQL_REDO
-------------------------------------------------------------------------------
ALTER PACKAGE "XDB"."DBMS_XSLPROCESSOR" COMPILE SPECIFICATION REUSE SETTINGS;
ALTER PACKAGE "XDB"."DBMS_XMLDOM" COMPILE SPECIFICATION REUSE SETTINGS;
ALTER PACKAGE "XDB"."DBMS_XMLPARSER" COMPILE SPECIFICATION REUSE SETTINGS;
ALTER PACKAGE "EXFSYS"."DBMS_RLMGR_DR" COMPILE BODY REUSE SETTINGS;
truncate
table developers;
...............................................................................
create table patient_diagnosis
(
patient_id number,
...............................................................................
create view vw_patient_diagnosis
as
...............................................................................
create or replace view vw_patient_diagnosis
as
...............................................................................
create or replace function pd_pol
(
p_schema in varchar2,
...............................................................................
create or replace function pd_pol
(
p_schema in varchar2,
...............................................................................
create or replace function pd_pol
(
p_schema in varchar2,
...............................................................................
grant connect, resource to ananda identified by VALUES '1DB10D95DE84E304' ;
create or replace function pd_pol
(
...............................................................................
create or replace function pd_pol
(
p_schema in varchar2,
...............................................................................
ALTER TABLE "ARUP"."TEST1" RENAME TO "BIN$JQHaX2mpSxOyrhkxAteHmg==$0" ;
drop table test1 AS "BIN$JQHaX2mpSxOyrhkxAteHmg==$0" ;
当然,该输出本身可能是没有任何意义;您必须察看更多的信息,例如 Log Miner 条目中的时间戳记、SCN、等等,在用户操作和实际事件之间进行有效的连接。
select timestamp, scn, seg_owner, seg_name
from lm_contents
where operation = 'DDL'
and seg_owner not in ('SYS','SYSTEM','PUBLIC')
/
下面是一个样例输出: TIMESTAMP SCN SEG_OWNER SEG_NAME --------- ---------- ---------- ------------------------------ 06-FEB-06 1024674 XDB DBMS_XSLPROCESSOR 06-FEB-06 1026884 XDB DBMS_XMLDOM 06-FEB-06 1026896 XDB DBMS_XMLPARSER 06-FEB-06 1026918 EXFSYS DBMS_RLMGR_DR 06-FEB-06 1029244 ARUP DEVELOPERS 08-FEB-06 1096847 ARUP PATIENT_DIAGNOSIS 08-FEB-06 1097057 ARUP VW_PATIENT_DIAGNOSIS 08-FEB-06 1097920 ARUP VW_PATIENT_DIAGNOSIS 08-FEB-06 1100059 ARUP PD_POL 08-FEB-06 1100157 ARUP PD_POL 08-FEB-06 1100386 ARUP PD_POL 08-FEB-06 1100413 ANANDA 08-FEB-06 1101544 ANANDA PD_POL 08-FEB-06 1101564 ARUP PD_POL 09-FEB-06 1123950 ARUP TEST1 09-FEB-06 1123953 ARUP TEST1 注意:我使用的是 SEG_OWNER,不是 USERNAME。 由于 Oracle 数据库 10.2.0.1 中的一个缺陷没有解决,USERNAME 没有放入进去。 这只是怎样从归档日志中抽取 DDL 语句的一个示例。 您也可以使用任何语句挖掘日志——DML。 DML 语句挖掘是对审计的重要代替,因为它们对数据库不施加任何性能压力。 提示 操作计划
该阶段的任务量比较少,但是这些任务执行起来却要花费很多时间。 另外,因为它们是目标的一部分,所有没有明晰的详细信息。 这些次要的细节变化很大,所以要进行综合的通用型描述是不可能的。 安全要求的最重要因素是要明白您不可能在真空中求得安全。 为了有效地构建一个安全的数据库基础架构,您的行为必须和对机构独特本质的理解协调起来,您的分析必须包括业务流程,从而将敏感数据和非敏感数据隔离开来。 例如,信用卡数在任何机构都将被保护,但是销售数怎么办呢? 在某些机构中(例如零售店),数据量相当庞大,加密保护就不适宜了。但是对冲基金商贸公司却是可行的, 在这里销售数据被严加保护。 查看敏感数据的一个分层方法可能实用于某些情况下;但是在大多数情况下,分层方法最可能按需提供。 即将结束时,我希望您已经学习到某些您现在就可以使用的有价值的工具和技巧来保护您的数据库基础架构。 如果您能花费一些时间让我了解您对第 4 阶段的反馈和改进建议,同时提供其它相关问题和资料,我将非常感谢。
这里提供的内容仅仅是为了教学,并没有得到 Oracle 的确认;使用这些内容后的结果自负。 无论如何您都不应该将这里提供的内容视为咨询或服务产品的一部分。
|