ORACLE使用透明数据库加密
--官网文档:https://www.oracle.com/technetwork/cn/tutorials/tde-096009-zhs.html#t
Oracle 数据库 10g 第 2 版透明数据库加密功能简化了信用卡号码以及社会安全保险号等机密我的信息的加密。 使用透明数据加密功能,没必要将加密例程嵌套到现有应用程序中,显著下降了加密的成本和复杂性。
大多数加密解决方案都须要在应用程序代码中对调用加密函数。 这样作开销很高,由于它一般须要深刻了解应用程序并要可以编写和维护软件。
经过 SQL 执行的应用程序逻辑不须要进行更改,仍能正常运行。 Oracle 数据库在将信息写入磁盘以前将自动对数据进行加密,随后的选择操做将透明地解密数据,所以应用程序将继续正常地运行。html
设置加密密钥:Oracle 透明数据加密提供了实施加密所必需的关键管理基础架构。 加密的工做原理是将明文数据以及秘密(称做密钥)传递到加密程序中。 加密程序使用提供的密钥对明文数据进行加密,而后返回加密数据。 以往,建立和维护密钥的任务由应用程序完成。 Oracle 透明数据加密经过为整个数据库自动生成一个万能密钥解决了此问题。 在启动 Oracle 数据库时,管理员必须使用不一样于系统口令或 DBA 口令的口令打开一个 Oracle Wallet 对象。 而后,管理员对数据库万能密钥进行初始化。 万能密钥是自动生成的。算法
性能:因为索引数据未被加密,所以加密一般会影响现有的应用程序索引。 Oracle 透明数据加密对与给定应用程序表关联的索引值进行加密。 这意味着应用程序中的相等搜索对性能的影响很小,甚至没有任何影响。 例如,假设应用程序 PERSON ID 存在一个索引,而且此应用程序执行如下语句:
--Oracle 数据库将使用现有的应用程序索引,尽管 PERSON ID 信息已经在数据库中加密。
SQL> Select rating from credit where person id = '23590';sql
建立一个包含加密列的表,为加密列建立一个索引,并授予访问某个用户的列的权限, 而后,您将建立一个包含对加密数据进行相应访问控制的函数,随后经过 VPD 策略应用该函数。
透明数据加密在数据写入磁盘以前对其进行加密,并在读取该数据时将其解密。 这对全部使用 SQL 层的应用程序都是透明的。 所以,没法轻松地验证数据是否真正被加密。 因为 Oracle LogMiner 对写入磁盘的数据进行记录,所以您能够访问该信息。数据库
准备用于加密的数据库
在本部份内容中,您将更新 sqlnet.ora、建立一个加密钱夹 (ewallet.p12)、打开此钱夹并为 TDE 建立万能密钥。执行如下操做:
1.您须要更新 sqlnet.ora 文件以包含一个 ENCRYPTED_WALLET_LOCATION 条目。打开一个终端窗口,而后输入如下命令:
cd $ORACLE_HOME/network/admin
gedit sqlnet.ora安全
--将如下条目添加到文件末尾,能够为加密钱夹选择任何目录,但路径不该指向在数据库安装过程当中建立的标准模糊钱夹 (cwallet.sso):
ENCRYPTION_WALLET_LOCATION=
(SOURCE=(METHOD=FILE)(METHOD_DATA=
(DIRECTORY=/u01/app/oracle/product/10.2.0/db_1/)))session
2.接下来,您须要打开钱夹并建立万能加密密钥。从终端窗口中,输入如下命令:
cd /home/oracle/wkdir
sqlplus /nolog
@tde00_dbsetup架构
--只有拥有“alter system”权限的用户才能建立万能密钥或打开钱夹;万能密钥只能建立一次,除非您想要使用新的加密密钥从新加密数据
connect / as sysdba
--若是指定的目录中不存在加密钱夹,则将建立加密钱夹 (ewallet.p12)、打开此钱夹并建立/从新建立 TDE 的万能密钥; 若是指定目录中存在加密钱夹,则将打开此钱夹并建立/从新建立 TDE 的万能密钥。
alter system set key identified by "welcome1";oracle
--须要打开钱夹(它在您关闭数据库时已经关闭),但您不但愿建立一个新的万能密钥
alter system set wallet open identified by "welcome1";app
因为每一个表都有各自的加密密钥,所以万能加密密钥是必需的。这些列密钥存储在数据库中。 因为钱夹只能存储有限数目的密钥,而且可伸缩性不高,所以使用万能密钥加密列密钥。 这样,您即可以拥有所需数量的列密钥,而且钱夹中只存储少许的万能密钥(包括过时密钥,当您某一天从旧的备份磁带解密数据时可能须要它)。 默认状况下,以上命令使用 192 位的高级加密标准 (AES192) 生成一个密钥。 也可使用 3DES,或使用较小或较大的 AES 加密位数。ide
--建立一个包含加密列的表,为加密列建立索引并授予数据的访问权限。执行如下操做:
1.首先须要建立一些用户。从 SQL*Plus 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@tde04_cridx
create index cust_payment_info_idx on cust_payment_info (credit_card_number);
5.须要向用户授予客户付款信息表的访问权限。 在本实例中,LSMITH 是惟一一个能够更新此信息的用户。 其余用户只能查看它。从 SQL*Plus 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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.要查看执行计划,请执行如下脚本:
@tde06a_review_xplan
select * from table (dbms_xplan.display_cursor);
3.表 user_encrypted_columns 将通知您哪一个列已经加密以及它的加密算法。从 SQL*Plus 会话中,执行如下脚本:
@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 策略
因为加密并不替换相应的访问控制,所以您将使用一个很是简单的 VPD 策略限制行的访问权限。 首先,您将检查登陆到数据库的用户是不是员工,而后将按信用卡号码限制 oe.cust_payment_info 的访问权限:
Card_A 从“34”或“37”开始 Janette King
Card_V 从“4”开始 Lindsay Smith
Card_M 从“5”开始 Louise Doran
若是查看加载到表中的数据,则会看到,受权用户将没法选择与“Albert Einstein”关联的信用卡号码。 只有避开访问控制策略的入侵者或不受这些策略约束的管理用户才能够选择它。 这能够对该表进行高度集中的审计。
执行如下操做:
1.首先须要建立包含信用卡和员工验证所需逻辑的表。从 SQL*Plus 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@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;
--使用 LogMiner 查看重作日志
因为 TDE 是在写入数据以前执行的而且对全部应用程序都是透明的,所以没法轻松地验证是否真正加密了数据。 因为 Oracle LogMiner 记录写入磁盘的数据,所以可使用它查看日志文件中包含的内容。执行如下步骤:
1.从 SQL*Plus 会话中,执行如下脚本:
@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
('+MY_DG2/racdb/onlinelog/group_3.263.562151437', DBMS_LOGMNR.NEW);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE
('+MY_DG2/racdb/onlinelog/group_2.262.562151433', DBMS_LOGMNR.ADDFILE);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE
('+MY_DG2/racdb/onlinelog/group_1.261.562151431', 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。
--在无加密列的状况下从新建立表,为显示在未对列进行加密的状况下将看到的内容之间的差别,要删除该表并在无加密列的状况下从新建立它。执行如下操做:
1.从 SQL*Plus 会话中,执行如下脚本:
@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 会话中,执行如下脚本:
@tde15_logminer2
connect / as sysdba;
EXECUTE DBMS_LOGMNR.ADD_LOGFILE
('+MY_DG2/racdb/onlinelog/group_3.263.562151437', DBMS_LOGMNR.NEW);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE
('+MY_DG2/racdb/onlinelog/group_2.262.562151433', DBMS_LOGMNR.ADDFILE);
EXECUTE DBMS_LOGMNR.ADD_LOGFILE
('+MY_DG2/racdb/onlinelog/group_1.261.562151431', 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 会话中,执行如下脚本:
@tde16_cleanup
connect system/oracledrop user JKING cascade;drop user LSMITH cascade;drop user LDORAN cascade;drop function f_policy_oe_cust_payment_info;connect oe/oedrop table cust_payment_info;exit;