DBCoffer与Oracle字符集问题探讨
作为一款Oracle数据安全增强产品,其中不可避免的需要对Oracle内部数据进行操作,其中主要是对Oracle里需要保护的数据进行加密处
引言
数据库保险箱(简称DBCoffer) 是一款基于Oracle扩展机制实现的,数据高度安全、应用完全透明、密文高效访问的Oracle数据安全增强产品。DBCoffer可以防止绕过防火墙的外部数据攻击、来自于内部的高权限用户的数据窃取、以及由于磁盘、磁带失窃等引起的数据泄密。
作为一款Oracle数据安全增强产品,其中不可避免的需要对Oracle内部数据进行操作,其中主要是对Oracle里需要保护的数据进行加密处理,但因为DBCoffer是Oracle外部实现对数据的保护处理后,然后再次导进数据库,其中涉及数据的出与进,就会有字符集兼容及字符集转换等相关问题产生,遇到相关问题时,如何才能从容应对,这就要求开发者及测试者具有一定的Oracle字符集知识基础,下面就以字符集的一些相关知识原理为切入点,然后从后面的问题中一步一步深入探讨。
1 Oracle字符集简介
Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系。ORACLE 支持国家语言的体系结构允许你使用本地化语言来存储,处理,检索数据。它使数据库工具,错误消息,排序次序,日期,时间,货币,数字,和日历自动适应本地化语言和平台。
影响Oracle数据库字符集最重要的参数是NLS_LANG参数。它的格式如下:
NLS_LANG =language_territory.charset
它有三个组成部分(语言、地域和字符集),每个成分控制了NLS子集的特性。其中: Language 指定服务器消息的语言,territory 指定服务器的日期和数字格式,charset 指定字符集。如:AMERICAN _ AMERICA. ZHS16GBK
从NLS_LANG的组成我们可以看出,真正影响数据库字符集的其实是第三部分。当用“select userenv('language') from dual” 语句进行查询时,数据库服务端返回“language_territory.charset” 的结构,则charset对应为当前连接数据库字符集,而此查询结果也可以作为配置客户端字符集的依据。
在数据存储方面,不得不提两个概念:数据库字符集和国家字符集。在安装Oracle时,可以指定数据库字符集和国家字符集,其作用是用本国语言和格式来存储、处理和检索数据,如用来存储CHAR, VARCHAR2, CLOB, LONG等类型数据。国家字符集实质上是为Oracle选择的附加字符集,主要作用是为了增强Oracle的字符处理能力,因为NCHAR数据类型可以提供对亚洲使用定长多字节编码的支持,只能在unicode编码中的AF16UTF16和UTF8中选择,用以存储NCHAR, NVARCHAR2, NCLOB等类型数据,默认值是AF16UTF16。
由于oracle字符集种类多,且在存储、检索、迁移oracle数据时多个环节与字符集的设置密切相关,因此在实际的应用中,数据库开发和管理人员经常会遇到有关Oracle字符集方面的问题。
2 Oracle常用字符集原理剖析
在最初的数据库统中,字符集只有一种ASCII,由于ASCII支持的字符很有限,因此随后又出现了很多的编码方案,这些编码方案大部分都是包括了ASCII,下面要谈到的Oracle字符集US7ASCII就是一个7位的ASCII字符集。当然要理清Oracle所有的字符集不是件容易的事,下面就从一些当前较常用的Oracle字符集编码进行简单说明。
2.1 单字节编码
单字节7位字符集,可以定义128个字符,最常用的字符集为 US7ASCII.
单字节8位字符集,可以定义256个字符,适合于欧洲大部分国家,例如:WE8ISO8859P1(西欧、8位、ISO标准8859P1编码 )
2.2 多字节编码
变长多字节编码,某些字符用一个字节表示,其它字符用两个或多个字符表示,变长多字节编码常用于对亚洲语言的支持,例如日语、汉语、印地语等,例如:AL32UTF8(其中AL代表ALL,指适用于所有语言)、 ZHS16GBK231280。
定长多字节编码,每一个字符都使用固定长度字节的编码方案,目前Oracle唯一支持的定长多字节编码是AF16UTF16,也是仅用于国家字符集。
2.3 Unicode编码
Unicode是一个涵盖了目前全世界使用的所有已知字符的单一编码方案,也就是说Unicode为每一个字符提供唯一的编码。UTF-16是Unicode的16位编码方式,是一种定长多字节编码,用2个字节表示一个Unicode字符,AF16UTF16是UTF-16编码字符集。UTF-8 是Unicode的8位编码方式,是一种变长多字节编码,这种编码可以用1、2、3个字节表示一个Unicode字符,AL32UTF8,UTF8、UTFE是UTF-8编码字符集。
当一种字符集(字符集A)的编码数值包含另一种字符集(字符集B)的全部编码数值,并且两种字符集相同编码数值代表相同的字符时,则字符集A是字符集B的超级,或称字符集B是字符集A的子集。由于US7ASCII是最早的Oracle数据库编码格式,因此有许多字符集是US7ASCII的超集,例如WE8ISO8859P1、ZHS16CGB231280、ZHS16GBK,Oracle内部字符集的转换只保证是由子集到超集的转换正常。
3 DBCoffer与Oracle的通信架构分析
有了上面字符集的基础知识后,再来谈DBCoffer的与Oracle的通信架构图,相信能够很快让你看懂图中有哪些地方涉及字符集的转换,如下图所示:应用程序与Oracle客户端、外部库与Oracle服务端、Oracle客户端与Oracle服务端、Oracle服务端与Exp导出及Imp导入与Oracle服务端,这里提到的点都是Oracle服务端直接通信且可能发生字符集。在DBCoffer下,主要是通过调用外部库,直接与DBCSecureService进行通信,从而对数据进行处理后再送回数据库,当然这仅仅是整个DBCoffer的冰山一角,下面我们就从通信两端字符一致与不一致情况来分别讨论可能发生的情况。
图 1
3.1 字符集一致时情况分析
相信大家都知道,在Oracle客户端与服务端之间,如果两端字符集一致是不会有字符集转换的,即在客户端输进去的是什么,那么数据库存储是就是什么,这就是为什么7位US7ASCII、8位WE8ISO8859P1及UTF8字符集类型时,对于中文数据支持也是相当的不错,但是用这些字符集来处理中文时,相应的客户端程序开发与维护难度也会增加不少,且乱码产生的可能性也比ZHS16GBK要高出不少。下面来看一个例子:JAVA THIN连接字符集为WE8ISO8859P1的Oracle数据库。
首先对于JAVA THIN连接,也可以看成是Oracle的一种客户端,至于这个“客户端”所采用的字符集,通常是以JAVA默认字符集为参考。经过实验,当用JAVA THIN方式连接Oracle时,当服务端字符集为ZHS16GBK和UTF8时,对于DML语句的执行和结果集的显示,是不用进行相关字符集的转换操作,而当Oracle数据库字符集为WE8ISO8859P1时,问题就来了,对于需要执行的SQL语句,尤其是包含中文数据的SQL语句必须要先进行一个转码过程,转码函数参考如下: