在Oracle 10g中出现了column encryption列加密特性,通过对列上的数据加密实现数据安全性的目的。当然实现这一加密特性是有代价的,一方面会导致所加密列数据每行所占磁盘空间字节数增长,另一方面会消耗更多的cpu和内存资源。 当使用Oracle的TDE(transparent data encryption)加密数据表的某一列时将导致该表上每行数据所占用的空间大致增加33-51个字节,这几十个字节用作以下用途:
针对加密列可以使用'nomac'和no salt选项来减少性能损耗,其中'no mac'选项用以允许Oracle省略在加密数据中产生和存放message authentication code(MAC,信息验证代码),如上文所述的这部分代码用以对加密值的完整性检查,会占用20个字节的空间。通过使用'nomac'选项可以有效较少加密和后续操作所额外消耗的cpu周期,同时为加密值的存储减少20个字节的开销。 另外no salt选项用以省略加密中加入的16个字节的随机字符串(string),在能保证列值都唯一的情况下(攻击者无法通过已知密文比对的方式来解密),使用该选项可以有效减少cpu周期和每个单元16字节的空间开销。
此外目前列加密不支持外键约束,造成这种限制的原因是每张表都有其唯一的密钥(encryption key);而表空间加密则不存在这种限制,即便某个从属表不在加密表空间上。
列加密特性对于表连接(table joining)来说是透明的,即便作为连接条件的列被加密了也是如此(join tables is transparent,even if the columns for join condition are encrypted)。同时分区键是不能作为加密列的,否则将出现ORA-28346: an encrypted column cannot serve as a partitioning column错误。 此外加密列索引存在诸多限制,总结加密列索引(Indexes On Encrypted Columns)的几个restrictions:
当然表空间加密也仍然存在一些限制:
- 其中20个字节用以对加密值的完整性检查,该部分可以通过'nomac'选项来省略
- 同时加密会填补加密值到16个字节(如果列本身长度不够的话),举例来说如果是9个字节长度的number类型,那么加密该number字段时就会需要将该数据填补到16个字节,也就是额外地多用了7个字节
- 加密时默认采用salt选项(default),salt是指一串长度为16个字节的随机string,在数据被正式加密前这串string将会被添加到列上,这种做法使得黑客无法通过比对已知的密文来匹配加密值(steal patterns of ciphertext to known ciphertext);salt总是位于加密数据的末尾;该部分可以通过no salt选项来省略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
SQL>
create
table
enctab (t1
int
encrypt);
Table
created.
SQL>
create
index
ind_enc
on
enctab(t1);
create
index
ind_enc
on
enctab(t1)
*
ERROR
at
line 1:
ORA-28338:
Column
(s) cannot be both indexed
and
encrypted
with
salt
SQL>
create
table
news (t1 varchar2(1) encrypt);
Table
created.
/*以默认的salt和mac选项创建示例用表 */
SQL>
insert
into
news
values
(
'1'
);
1 row created.
SQL>
commit
;
Commit
complete.
/* 该列本身的长度为1个字节 */
SQL>
select
dump(t1,16)
from
news;
DUMP(T1,16)
--------------------------------------------------------------------------------
Typ=1 Len=1: 31
/* 以下为该行的dump信息,可以看到加密值增长到了52字节 */
col 0: [52]
de 76 08 74 2a c0 e3 94 89 e6 a8 3b 22 54 ca e5 af 4d eb a0 26 a7 e5 c2 f5
c0 e5 3a a0 09 9a 08 fa 56 2a 92 a0 83 b3 7f 0b 99 03 ad 12 78 d4 03 ec 6e
b3 c2
|
1
2
3
4
5
|
oracledatabase12g.com>
create
table
Maclean (t1 varchar2(16) encrypt
no
salt
'nomac'
);
/* 注意这里的nomac要被单引号括起来 */
oracledatabase12g.com>
alter
table
table_name
modify
column_name encrypt [using ] [
no
salt] [
'nomac'
];
|
1
2
3
4
5
6
7
8
9
10
11
|
SQL>
create
table
man (t1
int
primary
key
);
Table
created.
SQL>
create
table
woman(t1
int
encrypt);
Table
created.
SQL>
alter
table
woman
add
constraint
fk
foreign
key
(t1)
references
man(t1);
alter
table
woman
add
constraint
fk
foreign
key
(t1)
references
man(t1)
*
ERROR
at
line 1:
ORA-28335: referenced
or
referencing FK
constraint
column
cannot be encrypted
|
- 只有使用no salt选项加密的列上才允许创建索引
- 加密列上不支持位图索引
- 加密列不支持外键
- 加密列上创建的索引只能做等式查询,因为不能做Range scan所以如between,like等非等式查询是不支持的;这种限制是由于索引中的数据也被加密了,所以实际上数据是以加密后的形式来排序的。所有非等式查询的条件均无法利用到索引,而使用全表扫描。
- 如果应用不使用等式查询的话,那么建议不要在加密列上创建索引,因为这样无益与性能,反而会增加性能开销。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
SQL>
select
tablespace_name,ENCRYPTED
from
dba_tablespaces
where
tablespace_name
in
(
'ENC'
,
'USERS'
);
TABLESPACE_NAME ENC
------------------------------ ---
ENC YES
USERS
NO
SQL>
create
table
tv tablespace enc
as
select
*
from
dba_objects;
Table
created.
SQL>
create
index
pk_tv
on
tv(object_id) tablespace enc;
Index
created.
SQL>
set
autotrace
on
;
SQL>
select
1
from
tv
where
object_id=9999;
1
----------
1
Execution Plan
----------------------------------------------------------
Plan hash value: 2009574168
--------------------------------------------------------------------------
| Id | Operation |
Name
|
Rows
| Bytes | Cost (%CPU)|
Time
|
--------------------------------------------------------------------------
| 0 |
SELECT
STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
|* 1 |
INDEX
RANGE SCAN| PK_TV | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified
by
operation id):
---------------------------------------------------
1 - access(
"OBJECT_ID"
=9999)
/* 将该索引移动至非加密表空间上 */
SQL>
alter
index
pk_tv rebuild tablespace users;
Index
altered.
SQL>
select
1
from
tv
where
object_id=9999;
1
----------
1
Execution Plan
----------------------------------------------------------
Plan hash value: 2009574168
--------------------------------------------------------------------------
| Id | Operation |
Name
|
Rows
| Bytes | Cost (%CPU)|
Time
|
--------------------------------------------------------------------------
| 0 |
SELECT
STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
|* 1 |
INDEX
RANGE SCAN| PK_TV | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified
by
operation id):
---------------------------------------------------
1 - access(
"OBJECT_ID"
=9999)
/* 可以看到虽然索引被移动到非加密表空间上但仍可以被利用到并range scan */
SQL>
create
bitmap
index
obj_typ
on
tv (object_type) tablespace users;
Index
created.
/* 创建位图索引也没有问题 */
|
- 加密表空间不能使用传统的exp/imp工具导入导出,而只能使用datapump工具
- 显然External Large Objects (BFILEs)这种存储在数据库外的外部大对象也不受支持。
本文转自maclean_007 51CTO博客,原文链接:http://blog.51cto.com/maclean/1277702