OBE 主页 > 10gR2 单实例 > 安全性

使用透明数据库加密

本教程介绍了如何使用透明数据库加密对磁盘上存储的数据进行加密。

30 分钟

本教程包括下列主题:

将鼠标置于此图标上以加载和查看本教程的所有屏幕截图。(警告:因为此操作会同时加载所有屏幕截图,所以网速较慢时,响应时间可能会比较长。)

注意:您还可以在下面的步骤中将光标放在每个单独的图标上,仅加载和查看与该步骤相关的屏幕截图。

Oracle 数据库 10g 第 2 版透明数据库加密功能简化了信用卡号码以及社会安全保险号机密个人信息的加密。使用透明数据加密功能,不必将加密例程嵌套到现有应用程序中,显著降低了加密的成本和复杂性。只需使用几个简单的命令即可对机密应用程序数据进行加密。

自动加密机密信息

大多数加密解决方案都需要在应用程序代码中对调用加密函数。这样做开销很高,因为它通常需要深入了解应用程序并要能够编写和维护软件。通常,大多数企业没有时间或相关的专业知识来修改现有应用程序,调用加密例程。Oracle 透明数据加密通过将加密功能深层次地嵌套到 Oracle 数据库,解决了加密问题。

通过 SQL 执行的应用程序逻辑不需要进行更改,仍能正常运行。换言之,应用程序可以使用同一语法将数据插入到应用程序表中,并且 Oracle 数据库在将信息写入磁盘之前将自动对数据进行加密。随后的选择操作将透明地解密数据,因此应用程序将继续正常地运行。这一点很重要,因为当前的应用程序通常期望未加密的应用程序数据。显示加密数据至少会使应用程序用户迷惑不解,甚至还会破坏现有的应用程序。

设置加密密钥

Oracle 透明数据加密提供了实施加密所必需的关键管理基础架构。加密的工作原理是将明文数据以及秘密(称作密钥)传递到加密程序中。加密程序使用提供的密钥对明文数据进行加密,然后返回加密数据。以往,创建和维护密钥的任务由应用程序完成。Oracle 透明数据加密通过为整个数据库自动生成一个万能密钥解决了此问题。在启动 Oracle 数据库时,管理员必须使用不同于系统口令或 DBA 口令的口令打开一个 Oracle Wallet 对象。然后,管理员对数据库万能密钥进行初始化。万能密钥是自动生成的。

性能

由于索引数据未被加密,因此加密通常会影响现有的应用程序索引。Oracle 透明数据加密对与给定应用程序表关联的索引值进行加密。这意味着应用程序中的相等搜索对性能的影响很小,甚至没有任何影响。例如,假设应用程序 PERSON ID 存在一个索引,并且此应用程序执行以下语句:

SQL> Select rating from credit where person id = '23590';

Oracle 数据库将使用现有的应用程序索引,尽管 PERSON ID 信息已经在数据库中加密。

在本教程中,您将创建一个包含加密列的表。您将为加密列创建一个索引,并授予访问某个用户的列的权限。该用户随后将更改数据。然后,您将创建一个包含对加密数据进行相应访问控制的函数,随后通过 VPD 策略应用该函数。

透明数据加密在数据写入磁盘之前对其进行加密,并在读取该数据时将其解密。这对所有使用 SQL 层的应用程序都是透明的。因此,无法轻松地验证数据是否真正被加密。由于 Oracle LogMiner 对写入磁盘的数据进行记录,因此您可以访问该信息。

1.

完成了教程在 Windows 上安装 Oracle 数据库 10g

2. 下载 tde.zip 并将其解压缩到您的工作目录 (c:\wkdir)

在本部分内容中,您将更新 sqlnet.ora、创建一个加密钱夹 (ewallet.p12)、打开此钱夹并为 TDE 创建万能密钥。执行以下步骤:

1.

选择开始 > 程序 > Oracle - OraDb10g_home1 > Application Development > SQL Plus。为 User Name 输入 /nolog,单击 OK

您需要更新 sqlnet.ora 文件以包含一个 ENCRYPTED_WALLET_LOCATION 条目。输入以下命令:

edit c:\oracle\product\10.2.0\db_1\network\admin\sqlnet.ora

在弹出的记事本中,将以下内容添加到文件末尾:

               

ENCRYPTION_WALLET_LOCATION= (SOURCE=(METHOD=FILE)(METHOD_DATA= (DIRECTORY=c:\oracle\product\10.2.0\db_1)))

保存您的更改并关闭文件。

注意:可以为加密钱夹选择任何目录,但路径不应指向在数据库安装过程中创建的标准模糊钱夹 (cwallet.sso)。

 

2.

接下来,您需要打开钱夹并创建万能加密密钥。执行以下脚本:

@c:\wkdir\tde00_dbsetup
connect / as sysdba
alter system set key identified by "welcome1";  

上面的 alter 命令执行以下任务:

注意:只有拥有“alter system”权限的用户才能创建万能密钥或打开钱夹。

万能密钥只能创建一次,除非您想要使用新的加密密钥重新加密数据!!!

在后面的部分中,您不希望使用上面提供的命令;您需要打开钱夹(它在您关闭数据库时已经关闭),但您不希望创建一个新的万能密钥。于是,使用以下命令:

alter system set wallet open identified by "welcome1"; 

由于每个表都有各自的加密密钥,因此万能加密密钥是必需的。这些列密钥存储在数据库中。由于钱夹只能存储有限数目的密钥,并且可伸缩性不高,因此使用万能密钥加密列密钥。这样,您便可以拥有所需数量的列密钥,并且钱夹中只存储少量的万能密钥(包括过期密钥,当您某一天从旧的备份磁带解密数据时可能需要它)。 默认情况下,以上命令使用 192 位的高级加密标准 (AES192) 生成一个密钥。也可以使用 3DES,或使用较小或较大的 AES 加密位数。

 

返回主题列表

在本教程中,您将创建一些用户,并创建一个包含加密列的表来存储信用卡信息。您将向该表中插入一些数据,为加密列创建索引并授予数据的访问权限。执行以下步骤:

1.

首先需要创建一些用户。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde01_crusers

connect system/oracle
prompt Create users: JKING, LSMITH and LDORAN
grant connect to JKING identified by welcome1;
grant connect, DBA to LSMITH identified by welcome1;
grant connect to LDORAN identified by welcome1; 

注意:您已经授予了 LSMITH DBA 角色,以演示 TDE 对相等性搜索索引的支持。因此,dbms_xplan 的输出应包含 INDEX RANGE SCAN

 

2.

接下来,您将创建一个表,其中包含一个用于存储加密(默认为 AES192)信用卡信息的列。由于 credit_card_number 列将有一个索引,因此指定 SALT,当对加密值进行 salt 处理时将不会生成索引。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde02_crtabl

connect oe/oe
create table cust_payment_info
(first_name varchar2(11),
last_name varchar2(10),
order_number number(5),
credit_card_number varchar2(16) ENCRYPT NO SALT,
active_card varchar2(3));

 

3.

现在,可以向刚刚创建的表中添加一些数据。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde03_poptabl

insert into cust_payment_info values
('Jon', 'Oldfield', 10001, '5446959708812985','YES');
insert into cust_payment_info values
('Chris', 'White', 10002, '5122358046082560','YES');
insert into cust_payment_info values
('Alan', 'Squire', 10003, '5595968943757920','YES');
insert into cust_payment_info values
('Mike', 'Anderson', 10004, '4929889576357400','YES');
insert into cust_payment_info values
('Annie', 'Schmidt', 10005, '4556988708236902','YES');
insert into cust_payment_info values
('Elliott', 'Meyer', 10006, '374366599711820','YES');
insert into cust_payment_info values
('Celine', 'Smith', 10007, '4716898533036','YES');
insert into cust_payment_info values
('Steve', 'Haslam', 10008, '340975900376858','YES');
insert into cust_payment_info values
('Albert', 'Einstein', 10009, '310654305412389','YES');

 

4.

为提高性能,您将为信用卡号码列创建一个索引。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde04_cridx

create index cust_payment_info_idx on cust_payment_info (credit_card_number);

 

5.

需要向用户授予客户付款信息表的访问权限。在本例中,LSMITH 是唯一一个可以更新此信息的用户。其他用户只能查看它。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde05_grant_access
grant select on oe.CUST_PAYMENT_INFO to LDORAN;
grant select, update on oe.CUST_PAYMENT_INFO to LSMITH;
grant select on oe.CUST_PAYMENT_INFO to JKING; 

 

返回主题列表

在本部分中,您将以 LSMITH 的身份对表进行更改。执行以下步骤:

1.

由于您授与了 LSMITH 更新访问权限,因此能够进行更改。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde06_make_update

prompt *** Connect as Lindsay Smith (Card_V)
conn LSMITH/welcome1;
update oe.CUST_PAYMENT_INFO set ACTIVE_CARD='NO' where CREDIT_CARD_NUMBER='4556988708236902';

 

2.

要查看执行计划,请执行以下脚本:

@c:\wkdir\tde06a_review_xplan

select * from table (dbms_xplan.display_cursor);

 

3.

user_encrypted_columns 将通知您哪个列已经加密以及它的加密算法。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde07_select_encrypt_col

connect oe/oe
col TABLE_NAME format a18;
col COLUMN_NAME format a19;
col ENCRYPTION_ALG format a17;
select * from user_encrypted_columns;

 

返回主题列表

由于加密并不替换相应的访问控制,因此您将使用一个非常简单的 VPD 策略限制行的访问权限。首先,您将检查登录到数据库的用户是否是员工,然后将按信用卡号码限制 oe.cust_payment_info 的访问权限:

Card_A 从“34”或“37”开始
Card_V 从“4”开始
Card_M 从“5”开始

如果查看加载到表中的数据,则会看到,授权用户将无法选择与“Albert Einstein”关联的信用卡号码。只有避开访问控制策略的入侵者或不受这些策略约束的管理用户才可以选择它。这可以对该表进行高度集中的审计。

执行以下步骤:

1.

首先需要创建包含信用卡和员工验证所需逻辑的表。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde08_crfunction

connect system/oracle;
prompt
prompt *** Create policy function to create the where-clause:
create or replace function f_policy_oe_cust_payment_info
-- Function must have the following parameters
(schema in varchar2, tab in varchar2)
-- Function will return a string that is used as a WHERE clause
return varchar2
as
v_manager_id number:=0;
is_employee number:=0;
v_user varchar2(20);
out_string varchar2(70) default '1=2 ';
begin
-- get session user
v_user := lower(sys_context('userenv','session_user'));
-- Is the user an employee 
begin
select manager_id into v_manager_id
from hr.employees
where lower(email) = v_user;
is_employee:=1;
exception
when no_data_found then
is_employee:=2;
end;
-- create where clause when user is authorized to see parts of the table
if is_employee=1 and lower(v_user)='jking' and v_manager_id=146 then
out_string := out_string ||'or CREDIT_CARD_NUMBER like ''34%'' or CREDIT_CARD_NUMBER like ''37%''';
elsif is_employee=1 and lower(v_user)='lsmith' and v_manager_id=146 then
out_string := out_string ||'or CREDIT_CARD_NUMBER like ''4%''';
elsif is_employee=1 and lower(v_user)='ldoran' and v_manager_id=146 then
out_string := out_string ||'or CREDIT_CARD_NUMBER like ''5%''';
end if;
return out_string;
end;

/

 

2.

现在,可以将该策略添加到 cust_payment_info 表中。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde09_addpolicy

prompt
prompt *** Add policy to 'oe.cust_payment_info' table:
begin
dbms_rls.add_policy('oe','cust_payment_info','ac_cust_payment_info', 'system','f_policy_oe_cust_payment_info', policy_type => dbms_rls.context_sensitive);
end;

/

 

返回主题列表

在本部分中,将以每个员工的身份连接以查看该策略是否起作用。有三个方面可以体现 TDE 的真正透明性:

加密列已经使用索引
即使加密存储了信用卡号码,VPD 策略中的 where 子句仍搜索明文格式的号码并检索相应的行。
对三名员工可见的行包含明文格式的信用卡号码。通常,员工甚至不知道已经加密存储了数据。

执行以下步骤:

1.

您将首先以 Janette King 的身份连接。她可以访问从“34”或“37”开始的 Card_A。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde10_testpolicy_jking

prompt
prompt *** Connect as Janette King (Card_A)
conn JKING/welcome1;
col CREDIT_CARD_NUMBER heading Card_A format a18;
select * from oe.CUST_PAYMENT_INFO order by CREDIT_CARD_NUMBER;

 

2.

您现在将以 Louise Doran 的身份连接。她可以访问从“5”开始的 Card_M。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde11_testpolicy_ldoran

prompt
prompt *** Connect as Louise Doran (Card_M)
conn LDORAN/welcome1;
col CREDIT_CARD_NUMBER heading Card_M format a18;
select * from oe.CUST_PAYMENT_INFO order by CREDIT_CARD_NUMBER;

 

3.

然后,您将以 Lindsay Smith 的身份连接。她可以访问从“4”开始的 Card_V。从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde12_testpolicy_lsmith

prompt
prompt *** Connect as Lindsay Smith (Card_V)
conn LSMITH/welcome1;
col CREDIT_CARD_NUMBER heading Card_V format a18;
select * from oe.CUST_PAYMENT_INFO order by CREDIT_CARD_NUMBER;

 

返回主题列表

由于 TDE 是在写入数据之前执行的并且对所有应用程序都是透明的,因此无法轻松地验证是否真正加密了数据。由于 Oracle LogMiner 记录写入磁盘的数据,因此可以使用它查看日志文件中包含的内容。执行以下步骤:

1.

从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde13_logminer

connect / as sysdba;
alter database add supplemental log data; REM select member as LOG_FILE_LOCATION from v$logfile;
EXECUTE DBMS_LOGMNR.ADD_LOGFILE ('c:\oracle\product\10.2.0\oradata\orcl\redo03.log', DBMS_LOGMNR.NEW);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE ('c:\oracle\product\10.2.0\oradata\orcl\redo02.log', DBMS_LOGMNR.ADDFILE);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE ('c:\oracle\product\10.2.0\oradata\orcl\redo01.log', DBMS_LOGMNR.ADDFILE)
prompt start LogMiner:
EXECUTE DBMS_LOGMNR.START_LOGMNR (options => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.COMMITTED_DATA_ONLY);
select sql_redo from v$logmnr_contents where
table_name = 'CUST_PAYMENT_INFO' and operation='INSERT';

LogMiner 不支持加密数据,因此 credit_card_number 列中的加密值显示为 Unsupported Type。

注意:如果在您自己的环境中运行本教程,则需要运行以下命令来确定日志文件名称,然后相应地修改脚本:

select member as LOG_FILE_LOCATION from v$logfile;

 

返回主题列表

为显示在未对列进行加密的情况下将看到的内容之间的差异,要删除该表并在无加密列的情况下重新创建它。执行以下步骤:

1.

从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde14_crtabl2

connect oe/oe
drop table cust_payment_info;
create table cust_payment_info
(first_name varchar2(11),
last_name varchar2(10),
order_number number(5),
credit_card_number varchar2(20),
active_card varchar2(3));
insert into cust_payment_info values
('Jon', 'Oldfield', 10001, 5446959708812985,'YES');
insert into cust_payment_info values
('Chris', 'White', 10002, 5122358046082560,'YES');
insert into cust_payment_info values
('Alan', 'Squire', 10003, 5595968943757920,'YES');
insert into cust_payment_info values
('Mike', 'Anderson', 10004, 4929889576357400,'YES');
insert into cust_payment_info values
('Annie', 'Schmidt', 10005, 4556988708236902,'YES');
insert into cust_payment_info values
('Elliott', 'Meyer', 10006, 374366599711820,'YES');
insert into cust_payment_info values
('Celine', 'Smith', 10007, 4716898533036,'YES');
insert into cust_payment_info values
('Steve', 'Haslam', 10008, 340975900376858,'YES');
insert into cust_payment_info values
('Albert', 'Einstein', 10009, 310654305412389,'YES');
create index cust_payment_info_idx on cust_payment_info (credit_card_number);
grant select on oe.CUST_PAYMENT_INFO to LDORAN;
grant select, update on oe.CUST_PAYMENT_INFO to LSMITH;
grant select on oe.CUST_PAYMENT_INFO to JKING;
prompt *** Connect as Lindsay Smith (Card_V)
conn LSMITH/welcome1;
update oe.CUST_PAYMENT_INFO set ACTIVE_CARD='NO' where CREDIT_CARD_NUMBER=4556988708236902;

 

返回主题列表

您现在可以重新运行 logminer 脚本来查看它所包含的内容。执行以下步骤:

1.

从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde15_logminer2

connect / as sysdba;
EXECUTE DBMS_LOGMNR.ADD_LOGFILE ('c:\oracle\product\10.2.0\oradata\orcl\redo03.log', DBMS_LOGMNR.NEW);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE ('c:\oracle\product\10.2.0\oradata\orcl\redo02.log', DBMS_LOGMNR.ADDFILE);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE ('c:\oracle\product\10.2.0\oradata\orcl\redo01.log', DBMS_LOGMNR.ADDFILE)
prompt start LogMiner:
EXECUTE DBMS_LOGMNR.START_LOGMNR (options => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.COMMITTED_DATA_ONLY);
select sql_redo from v$logmnr_contents where
table_name = 'CUST_PAYMENT_INFO' and operation='INSERT';

该列未加密,且 LogMiner 显示已写入磁盘的名文数据。

 

返回主题列表

要清理环境,请执行以下步骤:

1.

从 SQL*Plus 会话中,执行以下脚本:

@c:\wkdir\tde16_cleanup

connect system/oracle
drop user JKING cascade;
drop user LSMITH cascade;
drop user LDORAN cascade;
drop function f_policy_oe_cust_payment_info;
connect oe/oe
drop table cust_payment_info;

 

返回主题列表

在本教程中,您学习了如何:

准备用于加密的数据库
创建一个包含加密列的表
更改加密数据
应用 VPD 策略
使用 LogMiner 查看重做日志
在无加密列的情况下重新创建表
再次查看重做日志

返回主题列表

将鼠标移到该图标上可以隐藏所有屏幕截图。