Oracle Transparent Data Encryption 透明加密(二)

这个系列主要介绍了Oracle10gR2开始推出的透明加密(Transparent Data Encryption,简称TDE)。在上面一篇中,我们简单介绍了TDE的基本原理,以及如何配置使用TDE技术加密数据库中的数据。

 

TDE是在数据库层次进行数据保护加密的方法。存放在数据库中的数据都是经过加密处理,而加密密钥Key是分别存放在数据库内和独立数据库存储的。这样带来的好处是,一旦数据文件、硬盘丢失,非法获取到的数据内容是不可读的,实现了敏感数据加密。另一方面,数据在存入数据库、从数据库中读取的过程中,由数据库自动进行加解密处理,不需要开发人员额外的工作。实现了一定意义上的透明。

 

在本篇中,我们继续讨论TDE的加密处理机制在存储方面的效率,以及加入TDE后,对DML等操作带来的影响。最后,想从管理和开发的角度谈TDE带给应用的机遇与挑战。

 

TDE存储结构

 

在使用TDE的时候,通过指定数据列是否加密,来对数据进行透明的加解密处理。插入、修改和查询数据的时候,使用的都是明文信息。但是,保存在数据库文件中的内容,的确是加密过的内容。那么,在存储空间的使用上,加密处理过的数据是不是占据更少的空间呢。我们继续实验。

 

首先,我们创建两个相同条件的数据表。字段名称、类型全部一致,区别在于一个进行加密设置,而另一个不进行设置。

 

//建立数据表t

SQL> create table t

  2  (id number encrypt no salt primary key); //t的数据列id是加密列

 

Table created

 

//数据表t_no

SQL> create table t_no

  2  (id number primary key); //一般数据列id

 

Table created

 

建立两个数据表的作用在于对比,之后插入相同的数据信息。

 

//插入数据

SQL> insert into t values (10);

 

1 row inserted

 

SQL> insert into t_no values (10);

 

1 row inserted

 

SQL> commit;

Commit complete

 

数据已经插入,按照Oracle数据段分配原则:一个对象创建之后,默认分配一个区extents,包括八个数据块block。我们选择的数据比较简单,所以必然在一个数据块中。下面对数据块进行定位。

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno,

  2  dbms_rowid.rowid_block_number(rowid) block#

  3  from t;

 

       FNO     BLOCK#

---------- ----------

4                         5120

 

使用dbms_rowid包,可以根据rowid的信息定位到该行所在数据块的信息。rowid包括对象号+数据文件号+数据块号+行号(slot编号)。上面说明加密表t的一条记录在第四号文件中的5120块中。

 

接下来尝试将数据块导出dump处理。

 

//在有alter system权限的情况下,dump出指定的数据块信息;

SQL> alter system dump datafile 4 block 5120;

 

System altered

 

//获取跟踪文件位置,f_get_trace_name是自定义函数,用于获取trace文件位置;

SQL> select f_get_trace_name from dual;

 

F_GET_TRACE_NAME

--------------------------------------------------------------------------------

C:\TOOL\ORACLE\ORACLE\PRODUCT\10.2.0\ADMIN\OTS\UDUMP\ots_ora_7512.trc

 

获取到的trace文件,包括一个数据块的信息内容。其中,我们关注片段如下:

 

data_block_dump,data header at 0x8b08464

===============

tsiz: 0x1f98

hsiz: 0x14

pbl: 0x08b08464

bdba: 0x01001400

     76543210

flag=--------

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x1f70

avsp=0x1f5c

tosp=0x1f5c

0xe:pti[0]   nrow=1      offs=0

0x12:pri[0] offs=0x1f70

block_row_dump:

tab 0, row 0, @0x1f70

tl: 40 fb: --H-FL-- lb: 0x1  cc: 1

col  0: [36]

 ee 20 fa 3c ed 79 0a 91 d6 6f 68 90 43 1d 69 36 13 d9 cf c8 e3 3e 3a 56 66

 01 de 9b 21 69 5e 8a 66 99 bf 52

end_of_block_dump

End dump data blocks tsn: 4 file#: 4 minblk 5120 maxblk 5120

 

数据行row 0,第一个col 0的取值,是一个较长的字段,不能区分出取值10(插入数据值10)。

 

为了对比,我们再看一下数据表t_no的情况。

 

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno,

  2  dbms_rowid.rowid_block_number(rowid) block#

  3  from scott.t_no;

 

       FNO     BLOCK#

---------- ----------

         4       5392

 

说明:数据表t_no的行,在文件4号的数据块5392上。

 

SQL> alter system dump datafile 4 block 5392;

 

System altered

 

SQL> select f_get_trace_name from dual;

 

F_GET_TRACE_NAME

--------------------------------------------------------------------------------

C:\TOOL\ORACLE\ORACLE\PRODUCT\10.2.0\ADMIN\OTS\UDUMP\ots_ora_4372.trc

 

dump出的数据内容为:

 

data_block_dump,data header at 0x86e8464

===============

tsiz: 0x1f98

hsiz: 0x14

pbl: 0x086e8464

bdba: 0x01001510

     76543210

flag=--------

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x1f92

avsp=0x1f7b

tosp=0x1f7b

0xe:pti[0]   nrow=1      offs=0

0x12:pri[0] offs=0x1f92

block_row_dump:

tab 0, row 0, @0x1f92

tl: 6 fb: --H-FL-- lb: 0x1  cc: 1

col  0: [ 2]  c1 0b

end_of_block_dump

End dump data blocks tsn: 4 file#: 4 minblk 5392 maxblk 5392

 

同样一行数据,在相同内容下,没有加过密的数据相对比较小。只有一个行开始标记,和直接的数据值。

 

结论:使用TDE的情况下,数据库文件中保存的数据值是进行过加密的。加密过的列值一般要长于原始数据值,所以使用TDE之后数据表要比不使用大。

 

 

操作的性能损耗

 

TDE的加解密操作完全是建立在自动加解密基础上。插入数据、修改数据的时候会自动将数据加密后存放在数据表中;选择数据时会自动的将加密过的列值进行解密。

 

这种操作无形中是增加了数据操作的成本,那么增加比例如何?

 

首先我们看插入操作实验。

 

//插入

SQL> create table t

  2  (id number encrypt);

 

Table created

 

Executed in 0.062 seconds

 

SQL> select * from scott.t;

        ID

----------

 

Executed in 0.016 seconds

 

//插入操作脚本

declare

  i number;

begin 

  for i in 1..10 loop

     insert into scott.t

     select object_id from dba_objects;

    

     if (mod(i,2)=0) then

       commit;

     end if;    

  end loop;   

  commit;

end;

/

SQL>

 

PL/SQL procedure successfully completed

 

Executed in 14.914 seconds

 

SQL> select count(*) from scott.t;

 

  COUNT(*)

----------

    527990

 

Executed in 0.109 seconds

 

对只有一个加密字段的数据表t,插入超过52万条数据,使用了近15s的时间。

如果不使用加密功能,性能如下:

 

SQL> create table t_no

  2  (id number);

Table created

Executed in 0.031 seconds

 

//插入脚本结构与上述相同,此处略

 

SQL>

PL/SQL procedure successfully completed

 

Executed in 5.741 seconds

SQL> select count(*) from scott.t_no;

 

  COUNT(*)

----------

    527995

 

Executed in 0.062 seconds

 

对比之后,很容易发现两者的差异,同样的数据表结构(加密列除外),同样的脚本,同样的数据量。不使用TDE的时间只有不到6s,相当于使用TDE的三分之一。

 

使用筛选时的情况如下:

 

//搜索使用了加密列的数据表

SQL> select * from scott.t where id=1000;

 

        ID

----------

      1000

 

10 rows selected

 

Executed in 3.51 seconds

 

//未使用加密列的数据表搜索

SQL> select * from scott.t_no where id=1000;

 

        ID

----------

      1000

 

10 rows selected

 

Executed in 0.14 seconds

 

差异更加明显,在使用id作为条件的搜索方法中。使用TDE的搜索执行时间约4%,这也说明了使用ID进行查询条件的时候,解析条件还需要额外的成本。

 

Oracle的官方文档中,对于使用TDE的性能问题有所涉及,认为带来的损耗是可以接受的。一些文献中给出的经验值也认为损耗在20%-30%之间。但综合上面两个实验:使用TDE,起码在目前的版本中,还是会有比较大的性能问题。这是进行技术方案选型的一个重要方面考量。

 

 

TDE管理和开发

 

从目前的情况看,TDE的主要应用是在特定的数据列和特定的表空间(对表空间TDE的使用请参考官方文档教程)。在系列的两篇中,我们一直在强调TDE的两个大优势:其一是数据层面加密,加密密钥与数据文件分开,增加了保险系数。另一方面,是透明加密,无需直接的管理。

 

这也就是说,使用TDE只是保证了数据在数据库中安全的,而且在wallet打开的情况下,使用sql语句查询实际上是没有限制的。所以,笔者认为TDE的这种优势在运维层面上的意义是大于开发上面的意义,起码可以很快让应用中的数据库层面实现加密,无需应用层面的支持。

 

此外,TDE是不负责数据传输阶段加密的。数据从DBMS传出后,还是以明文方式传输到应用。实际上,还是需要使用安全传输的解决方案。

 

运维方面,要注意数据库外层主密钥key的保护,如果损坏或者丢失,造成损失的几率还是很高的。

 

综上所述:TDE是一个数据库层级的加解密解决方案。在无法修改应用、又需要对数据库明文保存的敏感信息变成加密过信息的需要下是很有效的、快速的方案。但是,考虑到TDE自身的局限,以及带来的性能瓶颈损耗,在系统架构方案设计和解决方案选择的阶段还是尽量避免使用。

请使用浏览器的分享功能分享到微信等