oracle数据库加密学习总结

作者: ldd600

安全就好比在寒冷的冬天里,您穿上好几件衣服或穿最庞大的冬天使用的夹克御寒。 但是,构建各防御层可能阻止不了最坚决的恶意入侵者,当然这也不会总能够防御合法用户盗窃公司财产。 这里的组最后一道防线是加密,通过加密,用户(或者恶意入侵者)只有使用密码才可以访问到数据。 没有密码的数据是无效的。 如果您保护了密码,您就保护了数据。请记住,加密不能替代其它层次的安全性。

对于网络,加密是确保全局安全地主要因素:而对于数据库,加密则是安全防御中地某一层,应该理智地对数据库进行加密,否则,在总体安全得不到任何加强的同时,有可能会降低系统的性能、可用性以及可访问性。加密和解密需要计算资源,因此,有可能会给数据库服务器增加额外的负载,或者服务器在大量的计算压力下的响应事件无法令人满意。同时,由于无法使用加密状态下的数据这一事实,使得数据库无法对数据进行有效地比较,也不能进行计算,而基本的数据操作也是无效的。加密不但向用户,而且数据库隐藏了数据。利用加密,还带来密钥管理的任务。如果不能妥善地管理密钥,则会在两方面遭遇灾难:第一,如果密钥泄漏,则会导致数据泄漏;第二:密钥丢失,则会导致数据永远不会再被解密。

 

到目前为止,Oracle 提供两种加密方式:

a)         加密 API 例如包 和 dbms_crypto (在 Oracle 数据库 10g 第 1 版和更高版本中)。 使用这些包,我们可以构建我们自己的基础架构,对数据进行加密。 这种方法的灵活性最强,但是构建和管理却相当复杂。

b)        透明的数据加密是 Oracle 数据库 10g 第 2 版和更高版本的一个特性;使用该特性后,我们就不必手动进行密码管理了。 数据库管理密码,但是正如名称所指,加密是透明的——数据仅仅以加密的方式存储而已。 当我们选择了这种方式,扩展性比较差。

在本次实验中,为了更好地理解数据库的加密机制,我们将采用第一种方法。在Oracle10g中出现了dbms_crypto替代了之前的dbms_obfuscation_toolkit,DBMS_CRYPTO增加了若干新的加密算法、哈希算法。DBMS_CRYPTO还撤销了对于public组的执行权限。对于DBMS_CRYPTO中的详细解释将在实验中分步介绍。在本次实验中我们将采用David knox提供的Data_Crypto软件包来对数据库进行加密、解密,完成本次实验。包中已经对密钥还有数据转换进行了处理,已经对DBMS_CRYPTO包做了封装。当然学生也可以直接用DBMS_CRYPTO来完成上述功能。

加密数据

      DBMS_CRYPTO支持DES加密、双密钥的3DES以及三密钥的3DES加密,采用三个不同大小的AES和RC4加密算法。DBMS_CRYPTO通过数字值如DBMS_CRYPTO.encrypt_aes,这些参数是包的全局变量,可通过包名.变量,看起来有点像java中static final类变量,c++中的static constant,还有用数字表示的分组加密模式,如CBC,CFB,ECB和OFB,以及填充模式PKCS5,、Zeros、ORCL或NONE。这些都作为常数变量,传递给加密函数,Oracle默认推荐CBC模式和PKCS5。

DBMS_CRYPTO包提供了一个加密函数和两个存储过程都取名为encypt,但参数不同,这就是PL/SQL的函数和过程重载,需要参数类型、参数数量和参数次序不同。函数基于RAW的数据类型,接受RAW数据类型的密钥、数据以及可选的初始向量(IV initialization vector)作为输入,并返回RAW数据类型。两道加密存储过程则始给予LOB数据类型,其中之一接收BLOB类型参数,而另外一道过程则接受CLOB类型参数,这两个存储过程都利用RAW数据类型的密钥和IV,而且它们都是利用BLOB数据类型的in out参数。

那我们怎么对字符型数据进行加密呢,那又为什么不采用字符型数据来存放密文呢?

对字符型和其他数据类型进行加密要用UTL_RAW..CAST_TO_RAW进行数据类型的转换。实验中采用的DATA_CRYPTO中提供的加密和解密函数已经完成了字符转换,不需要再手动进行转换了。为什么不采用字符类型来存放密文,是因为不同语言版本的Oracle数据库转换后的字符类型不同,当一个数据库中的密文移动到其他语言版本的数据库中将不能解密。所以选择了RAW和BLOB.

下面开始实验:

1)        首先我们在ldd600模式下安装DATA_CRYPTO包和创建一个员工表,它包括两个字段,ename,salary。

SQL> @cry_install.sql

2)        我们将对salary列进行加密,因为员工的工资也属于隐私。

加密之前

进行加密:SQL> update people

2         set salary=data_crypto.encrypt(salary,'sal key');

加密之后,

请问who能看的懂?但是注意我们存放的还是字符型,data_crypto包中的encrypt_char用来把字符型加密为RAW型。但是建表的时要指定salary列的类型为raw。这里就不试了。

我们看看这些数据如果为raw型是什么样子的

1)        查询时我们要对其进行解密,才能解读

SQL> select ename,data_crypto.decrypt(salary,'sal key') salary

  2     from people;

对照一下,和加密之前的数据完全相同。

哈希

   哈希就是通过哈希函数的方法,使明文数据转换成固定长度密文数据。哈希到目前为止还是是计算上不可逆的过程。在Oracle中它的用户的密码,也是通过哈希存放的。不过我们不能简单的把数据库用户的用户名哈希后来和DBA_USERS表中PASSWORD例进行比较,因为Oracle采用的是HMAC。

   DBMS_CRYPTO包提供了MD4、MD5和SHA-1哈希算法,其中一个函数接受RAW类型的数据,另外一个函数接受CLOB类型的数据,还有一个函数接受BLOB类型的数据,所有上述三个函数返回的都是RAW类型的数据。之所以返回的是RAW类型的数据,有一个重要的原因是因为哈希的输出是固定大小的,哈希算法接受任何大小的输入,并返回固定大小的输出。MD4和MD5返回的输出是128位,而SHA返回的输出是160位。DATA_CRYPTO包也封装了这些哈希函数,默认的是SHA。

1)        创建一个表euser,包括两列:ename和password,password是用户名经initcap函数处理过后的结果,initcap是把字符串的第一个字母改成大写,而其他字符改成小写。这个表的安装也会在执行cry_install.sql时安装

1)        更改paassword列为其哈希值

    SQL> update euser

2                 set password = data_crypto.hash (password);

      看看哈希后的euser表

      SQL> select ename , utl_raw.cast_to_raw (password) password

  2     from euser;

1)        这一步我们要编写一个函数用来验证密码是否正确

        SQL> @user_auth.sql

2)        通过下面的匿名过程显示如何进行密码认证。

        SQL> BEGIN

  2    IF (is_user_auth ('scott', 'scott'))

  3    THEN

  4      DBMS_OUTPUT.put_line ('Scott authenticated with "scott"');

  5    ELSE

  6      DBMS_OUTPUT.put_line ('Scott could not authenticate with "scott"');

  7    END IF;

  8 

  9    IF (is_user_auth ('scott', 'Scott'))

 10    THEN

 11      DBMS_OUTPUT.put_line ('Scott authenticated with "Scott"');

 12    ELSE

 13      DBMS_OUTPUT.put_line ('Scott could not authenticate with "Scott"');

 14    END IF;

 15  END;

 16  /

密钥管理

   在这个例子中,我们将通过数据库来进行密钥管理,也就是通过数据库中的表来管理用户的密钥。

1)        在数据库中有密钥管理员,他负责管理用户的密钥。首先要创建密钥中心表KM,用来存放用户名和密钥对,密钥是以密文的形式存放于密钥中心中。密钥管理员拥有一个主密钥用来对密钥中心中的密钥加密存储。

KM也是在cry_install.sql执行创建的

2)        为了创建密钥要编写能产生伪随机字符串的函数,随机密钥的产生我们需要利用DBMS_OBFUCATION_TOOLKIT包。运行 脚本创建产生一个随机字符串函数create_key,随机字符串是由一个参数作为种子产生的,函数返回产生的随机字符串。

SQL> @get_random.sql;

3)        创建一个函数由2步中的随机数产生用户名和随机密钥对,并存储在km中

      SQL>@create_key.sql;

   为用户ldd600产生一个32位的密钥并加密后存储在km中密文是48位

      SQL>exec create_key('ldd600');

4)现在要做的是密钥管理员把密文密钥取出,并把它解密。创建一个解密并读取密钥的存储过程。该存储过程输入参数位用户名,输出位该用户对应的所有密钥。

   SQL>@de_key.sql

 解密并读取32位密钥的明文

  SQL>exec de_key(‘ldd600’);

3)        接下来所要做的是将这个密钥明文发给用户ldd600,通知他该密钥。

包装机密代码

在前面一个例子5.5中我们密钥管理员的主密钥是存储在存储过程create_key和de_key中。攻击者只要按如下方式就可以看到该密码:

SQL> COL TEXT FORMAT A80

SQL> select text from dba_source where name='CREATE_KEY';

注意这里的CREATE_KEY一定要大写。查询结果如图5.1所示

将上面方法和windows的find,unix的grep命令结合起来使用,就很容易搜索的密码了,打开cmd。

C:\Documents and Settings\ldd600>sqlplus ldd600/seclab@secora @pass.sql

C:\Documents and Settings\ldd600>find /i "password" c:\find.txt

如上图容易就找到了密码的信息
 
 

消除此风险的最佳方法是使用 wrap 实用程序。 创建脚本文件以创建过程或函数后,请使用以下代码包装它:

  C:\Documents and Settings\ldd600>wrap  iname=d:\sql\create_key_01.sql  oname=d:\

sql\create_key_01.plb

  C:\Documents and Settings\ldd600>sqlplus ldd600/seclab@secora @create_key_01.plb

  SQL> col text format a80

SQL> select text

  2  from dba_source

  3   where name='CREATE_KEY'

  4  /

看看我们现在看到了什么

我们仍然可以使用exec create_key(‘用户名’);来调用存储过程:

SQL> exec create_key('scott');

PL/SQL procedure successfully completed

你可能感兴趣的:(ORACLE相关)