Oracle+11g+笔记(11)-数据库的安全管理
11、数据库的安全管理
11. 1 用户管理
11.1.1 创建用户
创建用户可以采用CREATE USER
命令来完成。下面是CREATE USER
命令的语法。
CREATE USER username IDENTIFIED BY password
OR IDENTIFIED EXTERNALLY
OR IDENTIFIED GLOBALLY AS 'CN=user'
[DEFAULT TABLESPACE tablespace]
[TEMPORARY TABLESPACE temptablespace]
[QUOTA[integer K[M]][UNLIMITED]ON tablespace]
[PROFILES profile_name]
[PASSWORD EXPIRE]
[ACCOUNTLOCK or ACCOUNT UNLOCK]
其中,部分选项的说明如下:
-
username
:用户名,一般由字母、数字和#
及_
构成,长度不超过30。 -
password
:用户口令,一般由字母、数字和#
及_
构成。 -
IDENTIFIED EXTERNALLY
:表示用户名在操作系统下验证,这个用户名必须与操作系统中定义的相同。 -
IDENTIFIED GLOBALLY AS 'CN=user'
:用户名由 Oracle 安全域中心服务器来验证,CN
名称表示用户的外部名。
-
DEFAULT TABLESPACE tablespace
:默认的表空间。 -
TEMPORARY TABLESPACE temptablespace
:默认的临时表空间。 -
[QUOTA[integer K[M]][UNLIMITED]ON tablespace]
:用户可以使用的表空间的字节数。 -
PROFILES profile_name
:资源文件的名字。 -
PASSWORD EXPIRE
:立即将口令设置为过期状态,用户再登录进入前必须修改口令。 -
ACCOUNT LOCK or ACCOUNT UNLOCK
:用户是否被加锁,默认的是不加锁。
(1)、创建用户,指定默认表空间和临时表空间
# 创建用户名为king01,口令为king01,默认表空间为users,临时表空间为temp的用户
create user king01 identified by king01 default tablespace users temporary tablespace temp;
有时为了避免用户在创建表或索引对象时占用过多的空间,可以配置用户在表空间上的磁盘限额。
(2)、创建用户,并配置磁盘限额
# 创建用户名为king02,口令为king02,默认表空间为users,临时表空间为temp的用户
# 并且不允许该用户使用 system 表空间
create user king02 identified by king02 default tablespace users temporary tablespace temp quota 0 on system;
(3)、创建用户,并配置用户在指定表空间上不受限制
# 创建用户名为king03,口令为king03,默认表空间为users,并且该用户使用users 表空间不受限制
create user king03 identified by king03 default tablespace users quota unlimited on users;
除非将一些基本的权限授予新的账户,否则账户甚至不可以登录。因此,至少需要授予CREATE SESSION
权限或
CONNECT
角色。对于Oracle Database 10g
版本及更早的版本,CONNECT
角色包含CREATE SESSION
权限以及其
他基本权限,如CREATE TABLE
和ALTER SESSION
。从Oracle Database 10g
版本2开始,CONNECT
角色只有
CREATE SESSION
权限,因此不提倡通过给用户赋予CONNECT
角色使用户获得CREATE SESSION
和CREATE
TABLE
权限。
(4)、使用户获得 CREATE SESSION
和 CREATE TABLE
权限
# 将 CREATE SESSION 和 CREATE TABLE 权限授予king01
grant create session,create table to king01;
在创建用户时,还需要注意以下几个方面的事项:
-
初始建立的数据库用户没有任何权限,不能执行任何数据库操作。
-
初始建立的数据库用户没有任何权限,所以为了使用户可以连接到数据库,必须为其授予
CREATE SESSION
权限。
-
如果建立数据库用户时不指定
TEMPORARY TABLESPACE
子句,Oracle 会将数据库默认临时表空间作为用户的临时表空间。
-
如果建立数据库用户时不指定
DEFAULT TABLESPACE
子句,Oracle 会将SYSTEM
表空间作为用户默认的表空间。
-
如果建立数据库用户时没有为表空间指定
QUOTA
子句,那么用户在特定的表空间的配额为0,用户将不能在相应的表空间上建立数据对象。
11.1.2 修改用户
通常,可以使用alter user
命令来改变用户的特征,alter user
命令的语法基本等同于create user
命令的语
法。
# 将用户 king01在USERS 表空间的限额改为500MB
alter user king01 default tablespace users quota 500M on users;
11.1.3 删除用户信息
可以使用drop user
命令来完成。此命令唯一的参数是需要删除的用户名以及cascade
选项。如果没有使用
cascade
选项,则必须显式删除该用户拥有的任何对象,或将这些对象转移到另一个模式。
# 删除用户 queen01,如果 queen01 拥有任何对象,也自动删除这些对象
drop user queen01 cascade;
11.1.4 查询用户
大量数据字典视图都包含与用户和用户特征相关的信息。下表列出了最常见的视图和表。通过查询这些表,可以获
得用户信息。
# 通过查询数据表DBA_USERS来获取用户USER1的信息
Select USERNAME,USER_ID,PASSWORD from DBA_USERS where username='USER1';USERNAME|USER_ID|PASSWORD|
--------+-------+--------+
USER1 | 94| |
11.2 虚拟专用数据库
虚拟专用数据库(Virtual Private Database,VPD
)将服务器实施的细粒度访问控制和安全应用程序上下文结合
起来。支持上下文的函数返回一个谓词,即where 子句,该子句自动附加到所有的 select 语句或其他 DML 语
句。换句话说,由VPD
控制的表、视图、同义词上的 select 语句将根据 where 子句返回行的子集,该子句由通过
应用程序上下文生效的安全策略函数自动生成。VPD的主要组成部分是行级别的安全性(RLS),也称为"细粒度的访
问控制(FGAC)"。
可以使用create context
命令创建应用程序上下文,并且使用程序包DBMS_RLS
管理VPD
策略。
11.2.1 基于行的 VPD
11.2.1.1 应用程序上下文
使用create context
命令,可以创建应用程序定义的属性名称,这些属性用于实施安全策略。此外,还可以定义
函数和过程的程序包名称,这些函数和过程用于设置用户会话的安全上下文。下面给出一个创建应用程序上下文的
实例。
-- 创建上下文
create context hr_security using vpd.emp_access;
-- 创建程序包
create or replace package emp_access as procedure set_security_parameters;
end;
# 下面对SYS_CONTEXT的调用将检索数据库会话的用户名和IP_ADDRESS
declareusername varchar2(30);ip_addr varchar2(30);
beginusername:=SYS_CONTEXT('USERENV','SESSION_USER');ip_addr:=SYS_CONTEXT('USERENV','IP_ADDRESS');
end;
# 类似地,可以在SQL select语句中使用SYS_CONTEXT函数
select SYS_CONTEXT('USERENV','SESSION_USER') username from dual;USERNAME|
--------+
SYS |
使用 USERENV
上下文和数据库中授权信息的一些组合,可以使用 DBMS_SESSION.SET_CONTEXT
,将值赋予所创
建的应用程序上下文中的参数。
dbms_session.set_context('HR_SECURITY','SEC_LEVEL','HIGH');
为了确保针对每个会话设置上下文变量,可以使用登录触发器来调用与该上下文关联的过程。前面提及,在分配的
程序包中只可以设置或改变上下文中的变量。下面是一个示例登录触发器,该触发器调用过程以建立上下文。
create or replace trigger vpd.set_security_parameters
after logon on database
beginvpd.emp_access.set_security_parameters;
end;
在该示例中,过程SET_SECURITY_PARAMETERS
将需要调用DBMS_SESSION.SET_CONTEXT
。
11.2.1.2 安全策略实现
示例模式正常工作后,就可以建立安全环境,下一步就是定义用于生成谓词的函数,这些谓词将附加到受保护表的
每个select 语句或DML命令。用于实现谓词生成的函数有两个参数:对象的拥有者、对象的名称。一个函数只可
以处理一种操作类型的谓词生成,例如 select,或者适用于所有的DML 命令,这取决于该函数如何关联受保护的
表。
下面的示例显示了包含两个函数的程序包主体:一个函数将用于控制select 语句中的访问,另一个函数将用于任何
其他的 DML 语句。
create or replace package body get_predicates isfunction emp_select_restrict(owner varchar2,object_name varchar2)return varchar2 isret_predicate varchar2(1000); -- where子句部分beginreturn ret_predicate;end emp_select_restrict;function emp_dml_restrict(owner varchar2,object_name varchar2)return varchar2 isret_predicate varchar2(1000); --where子句部分beginreturn ret_predicate;end emp_dml_restrict;
end; --package body
每个函数返回一个包含表达式的字符串,该表达式被添加到 select 语句或 DML 命令的 where子句中。用户或应
用程序永远不会看到这个WHERE子句的值,它在解析时自动添加到该命令。
开发人员必须确保这些函数总是返回有效的表达式。否则,任何对受保护表的访问总会失败。
11.2.1.3 使用 DBMS_RLS
内置的程序包 DBMS_RLS
包含大量子程序,DBA 使用这些子程序维护与表、视图和同义词关联的安全策略。需要
创建和管理策略的用户都必须被授予程序包SYS.DBMS_RLS
上的 EXECUTE
权限。
我们将要用到的是一个最常用的子程序ADD_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
);
其中,参数说明如下:
-
object_schema
:包含由策略保护的表、视图或同义词的模式。 -
object_name
:由策略保护的表、视图或同义词的名称。 -
policy_name
:添加到该对象的策略的名称。 -
function_schema
:拥有策略函数的模式。 -
policy_function
:函数名称,该函数为针对 object_name 的策略生成谓词。如果函数是程序包的一部分,则在此处必须也指定程序包名,用于限定策略函数名。
-
statement_types
:应用策略的语句类型。 -
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。 -
long_predicate
:该参数默认为 FALSE。如果它为 TRUE,谓词字符串最多可为32K 字节长。否则,限制为4000字节。
-
sec_relevant_cols
:实施列级别的 VPD,只应用于表和视图。在列表中指定受保护的列,使用逗号或空格作为分隔符。
-
sec_relevant_cols_opt
:允许在列级别VPD过滤查询中的行出现在结果集中,敏感列返回 NULL 值。该参数的默认值为NULL,如果不是默认值则需指定
DBMS_RLS.ALL_ROWS
,用于显示敏感列为NULL的所有列。
在下面的程序中,将名为 EMP_SELECT_RESTRICT
的策略应用于表HR.EMPLOYEES
。模式 VPD 拥有策略函数
get_predicates.emp_select_restrict
,该策略显式地应用于表上的 SELECT语句。
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',-
enable=>TRUE
);
因为没有设置 static_policy
,它默认为FALSE,这意味着该策略是动态的,并且在每次解析select 语句时检查
该策略。
使用子程序ENABLE_POLICY
是临时禁用策略的一种简单方法,并且不需要在以后将策略重新绑定到表。
dbms_rls.enable_policy
(
object_schema=>'HR',
object_name=>'EMPLOYEES',
policy_name=>'EMP_SELECT RESTRICT,
enable=>FALSE
);
如果为相同的对象指定多个策略,则在每个谓词之间添加AND条件。如果需要在多个策略的谓词之间使用OR条
件,则很可能需要修订策略。每个策略的逻辑需要整合到一个策略中,该策略在谓词的每个部分之间具有OR 条
件。
11.2.1.4 创建 VPD
下面我们将通过一个事例来说明如何创建一个 VPD
。
为了实现不同雇员在查询表中数据时,系统能够自动根据雇员地位和所属部门对查询进行限制(例如,部门经理
可以查看本部门所有雇员信息,但不能查询其他部门雇员信息;普通雇员只能查询自己的信息,不能查询其他雇员
信息),我们可以通过建立一个VPD
的方法来做到这一点。
【创建VPD的具体操作过程如下】
(1)、创建数据库用户,并为用户授权。
# 创建数据库用户,并为这些用户授予连接数据库的权利
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;
注意:用户SMAVRIS
是公司的 HR_REP
;用户 KMOURGOS
是所有存货管理员的经理,而DGRANT
是被KMOURGOS
管
理的一个雇员。
(2)、授予用户查询 HR.EMPLOYEES
表的权利,并创建用户和公司雇员的对应关系表。
# 授予用户查询HR.EMPLOYEES表的权利
grant select on hr.employees to public;
我们需要建立一个映射表,将雇员ID号映射到他们的数据库账户。通过雇员的ID编号我们可以方便地获取该雇员
所属部门和该雇员的地位,便于确定该雇员对应的数据库用户的查询权限。
# 创建用户和公司雇员的对应关系表
# 创建查找表 hr.emp_login_map
create table hr.emp_login_map(employee_id,login_acct) as select employee_id,email from hr.employees;
# 将hr.emp _login_map表上的 SELECT 权限授予数据库中的每个人
grant select on hr.emp_login_map to public;
(3)、创建一个VPD
用户账户并为其授予权限。
# 创建一个称为VPD的用户账户,并使该账户具有创建上下文和维护策略函数的权限
create user vpd identified by vpd01;
grant connect,resource,create any context,create public synonym to vpd;
连接到VPD
模式,创建称为HR_SECURITY
的上下文,并且定义用于设置应用程序上下文的程序包和过程。
connect vpd/vpd01@orcl;create context hr_security using vpd.emp_access;
create or replace package vpd.emp_access as procedure set_security_parameters;
end;
程序包 VPD.EMP_ACCESS
中的过程是可以设置上下文变量的唯一过程。VPD.EMP_ACCESS
的程序包主体如下:
create or replace package body vpd.emp_access isprocedure set_security_parameters isemp_id_num number;emp_login varchar2(50);beginemp_login:=sys_context('USERENV','SESSION_USER');dbms_session.set_context('HR_SECURITY','USERNAME',emp_login);begin-- 数据库用户名对应于HR.EMPLOYEES中的email地址select employee_id into emp_id_num from hr.emp_login_map where login_acct=emp_login;dbms_session.set_context('HR_SECURITY','EM_ID',emp_id_num);exceptionwhen no_data_found then -- 用户不在查找表时dbms_session.set_context('HR_SECURITY','EMP_ID',0);end;end; --procedure
end; --package body
在过程中,通过查询 USERENV
上下文来检索用户的模式,默认情况下为所有用户自动启用该上下文;然后,将该
模式赋给新创建的上下文 HR_SECURITY
中的变量USERNAME
。通过在映射表 HR.EMP_LOGIN_MAP
中进行查找来确
定另一个HR_SECURITY
上下文变量 EMP_ID
。如果已经登录的用户不在映射表中,则为其分配的EMP_ID
值为0。
为了让数据库中的每个用户都能够执行程序包 VPD.EMP_ACCESS
,我们需要把其上的 EXECUTE
权限授予每一个用
户。
# 为每个用户授予执行权限
grant execute on vpd.emp_access to PUBLIC;
另外,为了减少击键次数,我们为VPD.EMP_ACCESS
创建一个了同义词,从而在每次需要调用该程序包时,可以
通过使用同义词的方法减少击键次数。
# 创建同义词
create public synonym emp_access for vpd.emp_access;
为了确保在每个用户登录时为其定义上下文,我们将以SYS
身份连接到数据库,并且创建一个登录触发器,用
于在上下文中设置变量。
# 创建登录触发器
connect sys/sysroot@orcl as sysdba;create or replace trigger vpd.set_security_parametersafter logon on database
beginvpd.emp_access.set_security_parameters;
end;
每个连接到数据库的用户都要激活该触发器,如果激活触发器失败并且显示一个错误,那么常规用户将无法登录。
(4)、生成谓词。
生成谓词的目的就是为了在用户查询HR.EMPLOYEES
表中数据时,过滤掉该用户无权查看的数据,以实现根据用户
地位和所属部门对用户的查询进行限制的目的。
# 建立定义谓词的程序包
connect vpd/vpd01;# 创建包
create or replace package vpd.get_predicates asfunction emp_select_restrict(owner varchar2,object_name varchar2) return varchar2;
end get_predicates;# 创建包体
create or replace package body vpd.get_predicates isfunction emp_select_restrict(owner varchar2,object_name varchar2)return varchar2 isret_predicate varchar2(1000); --part of WHERE clausebegin-- 只允许查看员工自己的信息或者是被该员工直接管理的其他员工的信息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
一旦使用 DBMS_RLS
将该函数附加到表,将生成一个文本字符串,在每次访问表时将该文本字符串用于WHERE 子
句中。该字符串总是类似于:EMPLOYEE_ID=111 OR MANAGER_ID=101
。
和建立上下文环境的程序包一样,需要允许用户访问该程序包。
grant execute on vpd.get_predicates to PUBLIC;
create public synonym get_predicates for vpd.get_predicates;
(5)、最后使用 DBMS_RLS.ADD_POLICY
过程将策略函数附加到表。
exec 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');
到此为止,我们的VPD
就创建完毕了。
(6)、测试
下面我们对创建好的 VPD
进行测试,看其能否起到应有的作用。
测试1:使用 KMOURGOS
账号登录,尝试检索HR.EMPLOYEES
的所有行。
connect kmourgos/kmourgos622@orcl;select employee_id,first_name,last_name,email,job_id,salary,manager_id from hr.employees;
分析程序执行结果可以发现,KMOURGOS
只能看到自己的行和归属自己直接管理的雇员的行,其他部门雇员的信息
均没有出现。
测试2:使用DGRANT
账号登录,尝试检索 HR.EMPLOYEES
的所有行。
connect dgrant/dgrant507@orcl;select employee_id,first_name,last_name,email,job_id,salary,manager_id from hr.employees;
分析程序执行结果可以发现,DGRANT
只能看到自己的行,因为他是普通雇员,没有管理公司内的其他雇员。
测试3:使用 SMAVRIS
账号登录,尝试检索HR.EMPLOYEES
的所有行。
connect smavris/smavris702@orcl;select employee_id,first_name,last_name,email,job_id,salary,manager_id from hr.employees;
分析查询结果可以发现,SMAVRIS
只能看到自己的行。但是需要注意,SMAVRIS
属于人力资源(HR)部门,所以应
该能够看到表中的所有行。此外,SMAVRIS
应该是可以查看所有雇员薪水信息。因此,需要改变策略函数为向
SMAVRIS
和HR
部门中的其他雇员提供对 HR.EMPLOYEES
表的完全访问。此外,可以使用策略赋值中列级别的约
束来返回相同数量的行,但其中的敏感数据作为NULL 值返回。
为了达到上述目的,可以按照下面的说明对已经创建好的 VPD
进行修改。
# Step1 修改映射表。修改映射表,使其包括JOB_ID列。如果JOB_ID列的值是HR_REP,该雇员就属于HR部门。-- 暂时使策略失效
begin
dbms_rls.enable_policy
(
object_schema=>'HR',
object_name=>'EMPLOYEES',
policy_name=>'EMP_SELECT_RESTRICT',
enable=>FALSE
);
end;-- 删除原有的查找表 hr.emp_login_map
drop table hr.emp_login_map;-- 创建查找表 hr.emp_login_map
create table hr.emp_login_map(employee_id,login_acct,job_id) as select employee_id,email,job_id from hr.employees;-- 将 hr.emp_login_map表上的 SELECT 权限授予数据库中的每个人
grant select on hr.emp_login_map to public;
# Step2 修改过程 VPD.EMP_ACCESS,在过程 VPD.EMP_ACCESS中添加一个上下文变量,该上下文变量表明访问表的
# 用户的安全级别。改变 SELECT 语句,并且对DBMS_SESSION.SET_CONTEXT进行另一次调用
-- 创建包体
create or replace package body vpd.emp_access isprocedure set_security_parameters isemp_id_num number;emp_login varchar2(50);emp_job_id varchar2(50); -- 新增变量,用于保存员工的job_idbegin-- 数据库用户名对应于HR.EMPLOYEES中的email地址emp_login:=sys_context('USERENV','SESSION_USER');dbms_session.set_context('HR_SECURITY','USERNAME',emp_login);begin-- 修改后的查询语句,增加了读取员工的job_id值得功能select employee_id,job_id into emp_id_num,emp_job_id from hr.emp_login_map where login_acct=emp_login;--添加一个上下文变量HR_SECURITY,用于设置用户安全级别dbms_session.set_context('HR_SECURITY','EM_ID',emp_id_num);-- 根据员工是否属于HR部门,设置SEC_LEVEL的值为HIGH或NORMALdbms_session.set_context('HR_SECURITY','SEC_LEVEL',case emp_job_id when 'HR_PER' then 'HIGH' else 'NORMAL' end);exceptionwhen no_data_found then -- 用户不在查找表时dbms_session.set_context('HR_SECURITY','EMP_ID',0);end;end; --procedure
end; --package body
员工为HR_REP
职位时,将上下文变量 SEC_LEVEL
设置为 HIGH
,否则设置为NORMAL
。在策略函数中,需要检
查这个新的条件,因此策略函数也需要修改。
-- 创建包体
create or replace package body vpd.get_predicates isfunction emp_select_restrict(owner varchar2,object_name varchar2)return varchar2 isret_predicate varchar2(1000); --part of WHERE clausebeginif sys_context('HR_SECURITY','SEC_LEVEL')='HIGH' then -- 安全级别为HIGH时ret_predicate:=''; --where 子句中没有任何限制条件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
上述修改完成后,重新以SMAVRIS
身份登录,并运行查询,对结果进行分析,可以发现查询到的是
HR.EMPLOYEES
表中的所有行,因为SMAVRIS
在HR_SECURITY
上下文中的安全级别是HIGH
。
对 DGRANT
进行测试,可以发现他仍然只可以看到表中自己的行,因为他在HR_SECURITY
上下文中的安全级别是
NORMAL
。
11.2.2 基于列的VPD
为了实施只有HR雇员可以看到薪水信息的需求,需要稍微修改策略函数,启用具有列级别约束的策略。
exec 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',-
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 列的查询中
的任何行。
11.3 透明数据加密
数据加密可以增强数据的保密性和安全性。数据库用户可能具有访问表中大多数列的合法需求,但如果对其中一列
进行加密,并且用户不知道加密密钥,则无法使用相关的信息。同样的问题也适用于需要通过网络安全发送的信
息。
可以采用两种方法进行数据加密:一种方法是使用程序包 DBMS_CRYPTO
;另一种方法是透明数据加密,这种方法
以全局方式存储加密密钥,并包含加密整个表空间的方法。本节将重点介绍的是透明数据加密方法。
透明数据加密是一种基于密钥的访问控制系统,它依赖于外部模块实施授权。包含加密列的每个表都有自己的加密
密钥,加密密钥又由为数据库创建的主密钥来加密,加密密钥以加密方式存储在数据库中,但主密钥并不存储在数
据库中。重点要强调的是"透明"这一术语-当访问表中或加密表空间中的加密列时,授权用户不必指定密码或密
钥。
【下面我们通过一个完整的实例来说明如何进行透明数据加密。】
oracle_719">11.3.1 创建oracle信任书
# Step1 创建信任书并设置密钥
alter system set encryption key identified by "Zzuli#761016";
注意:将信任书密钥放在双引号中,这一点非常重要。如果不将信任书密钥用双引号引起来,则密码将映射所有小
写字母,信任书将不处于打开状态。
# Step2 打开信任书。数据库实例被停机并重新启动之后,如果此任务未以其他方式自动化,则需要使用
# alter system命令打开信任书
alter system set encryption wallet open identified by "Zzuli#761016";
# Step3 关闭信任书,通过关闭信任书,随时可以毫不费力地禁用对数据库中所有加密列的访问
alter system set encryption wallet close;
如果遇到ORA-28368: 无法自动创建 wallet
错误:
问题原因:wallet
默认保存目录未创建。
解决方案:查询wallet默认保存目录。
select * from v$encryption_wallet;WRL_TYPE|WRL_PARAMETER |STATUS|
--------+-------------------------------------+------+
file |D:\APP\ZHANGSHIXING\ADMIN\ORCL\WALLET|CLOSED|
创建目录:mkdir D:\APP\ZHANGSHIXING\ADMIN\ORCL\WALLET
11.3.2 加密表
可以加密一个或多个表的一列或多列(不能加密SYS
所拥有的对象),具体做法是,在create table
命令中的列的
数据类型后面添加 encrypt
关键字;或者是在已存在列的列名后面添加encrypt
关键字。
# 以scott身份登录、创建ZGGZB表并加密jj列、向表中插入两行信息
connect scott/tiger@orclCREATE TABLE ZGGZB
(
zgbh varchar2(10) not null,
zgxm varchar2(20) not null,
jj number(6,2) encrypt
);insert into ZGGZB values('01','张三',215);
insert into ZGGZB values('02','王五',192);
提示:以前有权访问jj
列的任何用户仍具有对此列的相同访问权,对用户来说,这完全是透明的。唯一的区别在
于,访问包含ZGGZB
表的操作系统文件的任何人都无法破译jj
列。
# 以SYS身份登录,并查询ZGGZB中的行
select * from scott.zggzb;ZGBH ZGXM JJ
---------- -------------------- ----------
01 张三 215
02 王五 192
对结果进行分析,可以发现查询结果和没有加密之前是完全一样的。
11.3.3 加密表空间
已存在的表空间不能加密,要加密已有表空间的内容,则必须用 ENCRYPTION
选项创建一个新的表空间,并将已
有的对象复制或移动到新的表空间。
11.4 对备份进行加密
从 Oracle 10g
开始就开始提供备份加密,即对备份出来的文件采用一定的加密算法,防止备份文件被拷贝到别
的地方后随意恢复。采用加密方法的备份,如果在异地还原(Restore)的话,需要提供正确的密码才能做到。对备
份进行加密的方法主要有以下几种:透明加密模式
、基于密码的加密模式
和混合加密模式
。
11.4.1 透明加密模式
这种方法不需要设置密码,很适合在本地的备份与恢复,如果备份不需要传到其他的机器上,建议采用这样的加密
方法。因为不需要密码,只需要配置加密/解密信任书,也就是 Oracle Encryption Wallet
。
启动这种形式的加密方法很简单,首先需要配置 Oracle Encryption Wallet
。透明加密的操作步骤如下:
# Step1 配置sqlnet.ora,设置加密方式与文件地址
ENCRYPTION_WALLET_LOCATION=(SOURCE=(METHOD=FILE)
(METHOD_DATA=(DIRECTORY=E:\app\Administrator\admin\orcl\wallet)
# Step2 创建wallet,包括设置密码、生成信任文件、并启动 wallet
alter system set encryption key identified by "Zzuli#761016";
# Step3 启动RMAN,并进行加密备份(备份时要确保wallet是open的)。
RMAN>configure encryption for database on;
RMAN>set encryption on;
对上述透明加密的效果可以通过下列步骤进行测试:
# Step 1 在命令行中输入rman target\,启动 RMAN
# Step2 执行如下的程序:
RMAN> startup mount;
RMAN> sql 'alter system set wallet open identified by "Zzuli#761016"';
RMAN> configure encryption for database on;
--采用透明加密方式
RMAN>set encryption on;
RMAN>backup database format='d:\backup\%d_%s.bak';
# Step3 关闭wallet,并删除users表空间下的所有数据文件,模拟损坏表空间
RMAN>alter system set encryption wallet close;
RMAN>RESTORE TABLESPACE users;
# 程序执行后,可以发现系统给出的错误提示信息是:无法解密备份,Wallet未打开。
# Step4 先打开 Wallet,接着恢复表空间
RMAN> sql 'alter system set wallet open identified by "Zzuli#761016"';
RMAN> RESTORE TABLESPACE users;
可以发现在第(3)步中遇见的问题已经解决,表空间被恢复了。
11.4.2 基于密码的加密模式
基于密码的加密是最简单的加密模式,在备份的时候可通过以下语句设置备份密码,然后备份数据库或对应的表空
间、数据文件等。
RMAN> set encryption on identified by "mypass" only;
RMAN> backup database;
恢复的时候,则需要指定解密的密码才可:
RMAN> set decryption identified by "mypass";
RMAN> restore database;
这种方法虽简单,但其存在一缺点,即密码是明文的。
对上述基于密码加密的效果可以通过如下操作进行测试:
# Step1 在命令行中输入rman target\,启动 RMAN。
# Step2 执行如下的程序
RMAN> startup mount;
RMAN> set encryption on identified by "mypass" only;
RMAN> backup database format='d:\backup\%d_%s.bak';
# Step3 关闭实例,并删除数据文件,模拟数据库损坏
RMAN> shutdown immediate;
# Step4 指定密码,进行正常恢复
RMAN> startup mount;
RMAN> set decryption identified by "mypass";
RMAN> restore database;
RMAN> alter database open;
11.4.3 混合加密模式
在透明模式下,启动了Oracle Encryption Wallet
,这样的备份是无法到别的机器上去恢复的。此时,可以通
过设置加密的密码,如使用命令:RMAN> set encryption on identified by "mypass"
进行加密的密码设
置。
对比密码方式,它仅仅是少了only
这个关键字,这种情况下,如果在本地备份与恢复,是不需要密码的,如果是
在异地恢复(如在别的机器上恢复该备份),只需要设置解密的密码即可。
RMAN> set decryption on identified by "mypass";
RMAN> restore database;
第三种方式是前面两种方式的混合模式,在此就不再继续测试了。