数据加密介绍
在Oracle数据库中实现数据加密是一项重要的安全措施,它可以保护存储在数据库中的敏感信息不被未授权访问。Oracle提供了多种数据加密方法,包括透明数据加密(TDE)、列级加密和使用内置加密函数等。以下是一些在Oracle中实现数据加密的详细步骤和方法:
1. 透明数据加密(TDE)
透明数据加密是一种在数据库层面上自动加密和解密数据的技术,不需要修改应用程序代码。Oracle的TDE功能支持列级和表空间级加密。
列级加密
- 创建加密列:在创建表时,可以指定某些列为加密列。
CREATE TABLE sensitive_data ( id NUMBER, social_security_number VARCHAR2(11) ENCRYPT );
复制
这里social_security_number
列将被加密存储。
- 加密现有列:可以对已存在的表添加加密列或将现有列转换为加密列。
ALTER TABLE existing_table ADD (new_encrypted_column VARCHAR2(50) ENCRYPT);
复制
表空间级加密
创建加密表空间
- 创建加密表空间:在创建表空间时,可以指定使用加密。
CREATE TABLESPACE encrypted_ts ENCRYPTION = ENCRYPT;
复制
使用表空间透明数据加密(TDE)的限制
TDE 表空间加密方式会在数据读写过程中加解密数据。与在 SQL 层面做加解密的 TDE 列加密方式相比,其限制要大幅减少。例如:数据类型、索引类型的限制。但 TDE 表空间加密方式仍存在如下限制:
(TDE tablespace encryption encrypts/decrypts data during read/write operations, as opposed to TDE column encryption, which encrypts/decrypts data at the SQL layer. This means that most restrictions that apply to TDE column encryption, such as data type restrictions and index type restrictions, are not applicable to TDE tablespace encryption.The following list includes the restrictions that apply to TDE tablespace encryption:)
(1).如 BFILE 等外部大型对象无法使用 TDE 表空间加密(External Large Objects (BFILEs) cannot be encrypted using TDE tablespace encryption. This is because these files reside outside the database.)
(2).无法使用 IMP/EXP 导入导出,只能使用过 IMPDP/EXPDP(To perform import and export operations, use Oracle Data Pump.)
使用表空间透明数据加密(TDE)步骤
设置表空间主密钥(Master Encryption Key)
创建 wallet 目录(oracle,每个节点)
例如:创建 wallet 目录于 $ORACLE_BASE/admin/SID 下。
mkdir /u01/app/oracle/admin/zszracdb/wallet
复制
指定 wallet 路径(oracle,每个节点)
在 $ORACLE_HOME/network/admin 下的 sqlnet.ora 中设置 ENCRYPTION_WALLET_LOCATION 参数,指定软件 wallet 路径。其中,在 sqlnet.ora 文件中添加的条目如下。
ENCRYPTION_WALLET_LOCATION= (SOURCE= (METHOD=FILE) (METHOD_DATA= (DIRECTORY=/u01/app/oracle/admin/zszracdb/wallet) ) )
复制
检查 sqlnet.ora 信息读取状态(oracle,任一节点)
SQL> select * from v$encryption_wallet; select * from gv$encryption_wallet;
复制
注意:确保 v$encryption_wallet 与 gv$encryption_wallet 的 wallet location 是一致的。
注意:对于 wallet 分别在不同节点的情况以及 sqlnet.ora 在加入 ENCRYPTION_WALLET_LOCATION 参数前已经被数据库各实例读取的情况,需要重启各个实例以初始化 wallet 的状态,从而更新 gv$encryption_wallet 的 wallet location。
(In the case of RAC environments, if a separate wallet is being used for each node and if the changes to the sqlnet.ora file are applied on all instances of a running RAC system, restarting the individual instances one by one is necessary to initially synchronize the wallet status and to update the view gv$encryption_wallet with the DIRECTORY entry from sqlnet.ora.)
创建主密钥(oracle,任一节点)
注意:TDE 列加密与 TDE 表空间加密使用一个统一的主密钥。
例如:创建密码为 password 的主密钥语句如下所示。
SQL> ALTER SYSTEM SET ENCRYPTION KEY IDENTIFIED BY "password";
复制
注意:对于 RAC 环境而言,需要在执行语句的节点上,将创建出来的主密钥文件拷贝至其他节点的对应目录下。
打开 Oracle wallet(oracle,任一节点)
在创建加密表空间之前,包含有表空间主密钥的 Oracle wallet 必须处于打开状态。
先尝试关闭 Oracle wallet
SQL> ALTER SYSTEM SET ENCRYPTION WALLET CLOSE IDENTIFIED BY "password";
复制
打开 Oracle wallet
SQL> ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY "password";
复制
检验 Oracle wallet 状态
SQL> SELECT * FROM GV$ENCRYPTION_WALLET;
复制
若 TDE 密钥打开,则显示类似如下结果。
创建加密表空间(oracle,任一节点)
例如:创建加密数据表空间 JM_ZSZ_DATA 以及加密索引表空间 JM_ZSZ_IDX,语句类似如下。
SQL> CREATE TABLESPACE JM_ZSZ_DATA DATAFILE '+DATA' SIZE 1024M ENCRYPTION USING 'AES128' DEFAULT STORAGE(ENCRYPT); SQL> CREATE TABLESPACE JM_ZSZ_IDX DATAFILE '+DATA' SIZE 1024M ENCRYPTION USING 'AES128' DEFAULT STORAGE(ENCRYPT);
复制
检查表空间属性(oracle,任一节点)
查看个表空间的加密属性,确定新建表空间为 TDE 加密表空间。
SQL> SELECT tablespace_name, encrypted FROM dba_tablespaces;
复制
验证加密表空间(oracle,任一节点)(可选)
可通过此步骤验证加密表空间是否真正有效。
创建测试表
例如:创建加密表空间 JM_ZSZ_DATA 以及非加密表空间 BJM_ZSZ_DATA。随后分别在两个表空间内创建表 JM_TABLE 以及非加密表 BJM_DATA,语句类似如下。
SQL> create table jm_table(col1 number, col2 varchar2(30)) tablespace jm_zsz_data; create table bjm_table(col1 number, col2 varchar2(30)) tablespace bjm_zsz_data;
复制
创建后分别插入测试数据。
SQL> insert into jm_table values (1,'secret data'); insert into bjm_table values (1,'no secret data');
复制
测试 Oracle wallet 不打开时的读取状态
若 Oracle wallet 不打开,则无法读取加密表空间中的表,类似如下结果。
而非加密表读取正常,类似如下结果。
测试数据文件保存形式
通过 string 直接查看数据文件内容,如果非加密则可直接查见数据内容。对于加密数据文件,查询结果如下
注意:可见非以明文方式保存数据于 TDE 表空间加密的数据文件中。
对于非加密数据文件,查询结果如下。
注意:可见正常的数据文件中,以明文形式保存数据。
Oracle内部有专门的加密包,可以很方便的对内部数据进行加密(encrypt)和解密(decrypt).
介绍加密包之前,先简单说一下Oracle基本数据类型——RAW类型。
RAW,用于保存位串的数据类型,类似于CHAR,声明方式RAW(L),L为长度,以字节为单位,作为数据库列最大2000,作为变量最大32767字节。
操作RAW类型的函数:
utl_raw.cast_to_raw([varchar2]):将varchar2转换为raw类型
utl_raw.cast_to_varchar2([raw]):将raw转换为varchar2类型
hextoraw():十六进制字符串转换为raw
rawtohex():将raw串转换为十六进制
注:RAW保存的为16进制数,当使用HEXTORAW时,会把字符串中数据当作16进制数。而使用UTL_RAW.CAST_TO_RAW时,直接把字符串中每个字符的ASCII码存放到RAW类型的字段中。
eg>select hextoraw('abc') from dual; --输出结果为: ABC
eg>select utl_raw.cast_to_raw('abc') from dual; --输出结果为: 616263(a的ASCII码值为97,转换成16进制数为61)
加密包
下面介绍一下Oracle中的加密包:
dbms_obfuscation_toolkit(9i)
利用Dbms_Obfuscation_Toolkit包,我们可以对数据进行DES,Triple DES或者MD5加密
DESGETKEY -- 产生密钥,用于DES算法 DES3GETKEY -- 产生密钥,用于Triple DES算法 DESENCRYPT -- 用DES算法加密数据 DESDECRYPT -- 用DES算法解密数据 DES3ENCRYPT -- 用Triple DES算法加密数据 DES3DECRYPT -- 用DES算法解密数据 MD5 -- 用MD5算法加密数据
复制
加密包中分别采用raw和string两种数据类型加密,分别测试一下:(注:加密的字符串(input_string)必须是8的倍数)
DES算法加密解密
DECLARE v_input VARCHAR2(100) := '12345678'; v_key VARCHAR2(100) := 'oracle9i'; -- ORA-28232: obfuscation 工具箱的输入长度无效(原因是加密字符串必须是8的倍数) encrypted_str VARCHAR2(4000); decrypted_str VARCHAR2(4000); encrypted_raw RAW(4000); decrypted_raw RAW(4000); BEGIN -- string类型加密解密 -- encrypt(string) dbms_obfuscation_toolkit.desencrypt(input_string => v_input, key_string => v_key, encrypted_string => encrypted_str); dbms_output.put_line('Encrypted string: ' || encrypted_str); dbms_output.put_line('Encrypted hex value: ' || utl_raw.cast_to_raw(encrypted_str)); -- decrypt(string) dbms_obfuscation_toolkit.desdecrypt(input_string => encrypted_str, key_string => v_key, decrypted_string => decrypted_str); dbms_output.put_line('Decrypted String: ' || decrypted_str); -- raw类型加密解密 -- encrypt(raw) dbms_obfuscation_toolkit.desencrypt(input => utl_raw.cast_to_raw(v_input), key => utl_raw.cast_to_raw(v_key), encrypted_data => encrypted_raw); dbms_output.put_line('Encrypted Raw: ' || encrypted_raw); dbms_output.put_line('Encrypted hex value: ' || rawtohex(encrypted_raw)); -- decrypt(raw) dbms_obfuscation_toolkit.desdecrypt(input => encrypted_raw, key => utl_raw.cast_to_raw(v_key), decrypted_data => decrypted_raw); dbms_output.put_line('Decrypted String: ' || utl_raw.cast_to_varchar2(decrypted_raw)); END;
复制
注:DES算法加密的key长度必须大于等于8,而且加密的结果只跟其前8位有关(推测可能是截取了字符串);
Triple DES算法加密(DES3ENCRYPT)用法同DES基本类似,安全性叫DES算法更高;
同理,Triple DES算法的key长度必须大于等于16,且结果只与其前16位有关;
(Extra:数据类型PLS_INTEGER可以存储一个有符号的整型值,其精度范围和BINARY_INTEGER一样,是-2^31~2^31)
MD5算法加密
DECLARE v_str VARCHAR2(100) := '123456'; v_key VARCHAR2(100) := 'oracle9i'; encrypted_str VARCHAR2(32); encrypted_raw RAW(32); BEGIN -- encrypted as string dbms_obfuscation_toolkit.MD5(input_string => v_str || v_key, checksum_string => encrypted_str); dbms_output.put_line('Encrypted String: ' || encrypted_str); dbms_output.put_line('Encrypted hex value: ' || utl_raw.cast_to_raw(encrypted_str)); -- encrypted as raw dbms_obfuscation_toolkit.MD5(input => utl_raw.cast_to_raw(v_str || v_key), checksum => encrypted_raw); dbms_output.put_line('Encrypted Raw: ' || encrypted_raw); dbms_output.put_line('Encrypted hex value: ' || rawtohex(encrypted_raw)); END;
复制
注:MD5算法只能正向加密,但它多次对于同一数据的加密计算结果是相同的。
dbms_crypto(10g以后)
dbms_crypto包默认只有sysdba用户才可执行,其他任何用户都需要sysdba进行授权。
Oracle的DBMS_CRYPTO包提供了丰富的加密和解密功能,支持多种加密算法,如AES、DES等。
sys>grant execute on dbms_crypto to scott;
复制
加密数据
这里使用了AES-256算法进行加密。
BEGIN v_encrypted_data := DBMS_CRYPTO.ENCRYPT( src => UTL_RAW.CAST_TO_RAW('Sensitive data'), typ => DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5, key => your_encryption_key, iv => your_initialization_vector ); END;
复制
解密数据
BEGIN v_decrypted_data := DBMS_CRYPTO.DECRYPT( src => v_encrypted_data, typ => DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5, key => your_encryption_key, iv => your_initialization_vector ); END;
复制
示例:
-- 示例(不考虑BLOB类型的加密) DECLARE v_str VARCHAR2(20) := '12345678'; -- 加密的字符串 v_type PLS_INTEGER := dbms_crypto.DES_CBC_PKCS5; -- 加密类型 v_key RAW(256); v_key1 VARCHAR2(100) := 'oracle9i012'; encrypted_raw RAW(256); decrypted_raw RAW(256); BEGIN -- 生成随机16位密钥 (1个byte等于两位raw) v_key := dbms_crypto.RandomBytes(8); dbms_output.put_line('Encrypted Key: ' || v_key); -- 加密 encrypted_raw := dbms_crypto.Encrypt(src => utl_raw.cast_to_raw(v_str), typ => v_type, key => v_key); dbms_output.put_line('Encrypted Raw: ' || encrypted_raw); dbms_output.put_line('Encrypted hex value: ' || rawtohex(encrypted_raw)); -- 解密 decrypted_raw := dbms_crypto.Decrypt(src => encrypted_raw, typ => v_type, key => v_key); dbms_output.put_line('Decrypted String: ' || utl_raw.cast_to_varchar2(decrypted_raw)); END;
复制
可以加加密和解密的内容写入函数中,方便使用的时候直接调用。
数据脱敏
数据脱敏是另一种保护敏感数据的方法,它通过将敏感数据转换为非敏感形式来防止数据泄露。
使用函数进行脱敏:
SELECT DBMS_CRYPTO.HASH( src => UTL_RAW.CAST_TO_RAW(social_security_number), typ => DBMS_CRYPTO.HASH_MD5 ) FROM sensitive_data;
复制
总结
在Oracle中实现数据加密可以通过多种方式,包括使用TDE、DBMS_CRYPTO包或数据脱敏技术。选择合适的加密方法取决于具体的安全需求和业务场景。务必确保密钥的安全管理,以防止加密措施被绕过。对于更高级的加密需求,可以考虑使用Oracle Advanced Security提供的额外功能。