[toc]
适用范围 oracle 通过在线重定义将表中字段的数据进行加密。
不采用 tde的方式,oracle 超大表,业务尽可能无感知的将表中的某个字段变成加密存储,这里采用在线重定义的方式,对业务尽可能少的影响,通常少于5秒钟。
方案概述 oracle 通过在线重定义将表中字段的数据进行加密。
实施步骤 创建示例表 1 2 3 4 5 CREATE TABLE t ( id NUMBER PRIMARY KEY, name VARCHAR2(100 ), create_date DATE DEFAULT SYSDATE );
插入测试数据 1 2 3 4 5 6 7 BEGIN FOR i IN 1. .100 LOOP INSERT INTO t (id, name) VALUES (i, 'Name_' || i); END LOOP; COMMIT ; END ;/
创建加密函数 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 CREATE OR REPLACE FUNCTION encrypt_name(p_name IN VARCHAR2)RETURN RAW DETERMINISTIC IS v_max_length CONSTANT NUMBER := 2000 ; v_key RAW(32 ) := UTL_I18N.STRING_TO_RAW('32ByteAES256KeyForStrongSecurity' , 'AL32UTF8' ); v_src RAW(32767 ); BEGIN IF p_name IS NULL THEN RETURN NULL ; END IF; IF UTL_RAW.LENGTH(UTL_I18N.STRING_TO_RAW(p_name, 'AL32UTF8' )) > (v_max_length - 16 ) / 1.0 THEN RAISE_APPLICATION_ERROR(-20001 , 'Name 值过长,加密后长度超过 ' || v_max_length || ' 字节' ); END IF; v_src := UTL_I18N.STRING_TO_RAW(p_name, 'AL32UTF8' ); RETURN DBMS_CRYPTO.ENCRYPT( src = > v_src, typ = > DBMS_CRYPTO.AES_CBC_PKCS5, key = > v_key ); END ;/
创建解密函数 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 CREATE OR REPLACE FUNCTION decrypt_name(p_encrypted_raw IN RAW) RETURN VARCHAR2DETERMINISTIC IS v_key RAW(32 ) := UTL_I18N.STRING_TO_RAW('32ByteAES256KeyForStrongSecurity' , 'AL32UTF8' ); v_decrypted_raw RAW(32767 ); BEGIN IF p_encrypted_raw IS NULL THEN RETURN NULL ; END IF; v_decrypted_raw := DBMS_CRYPTO.DECRYPT( src = > p_encrypted_raw, typ = > DBMS_CRYPTO.AES_CBC_PKCS5, key = > v_key ); RETURN UTL_I18N.RAW_TO_CHAR(v_decrypted_raw, 'AL32UTF8' ); EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20002 , '解密失败:' || SQLERRM|| ' [检查密钥一致性及输入数据类型]' ); END ;/
创建在线重定义的临时表 1 2 3 4 5 CREATE TABLE t_temp ( id NUMBER PRIMARY KEY, name RAW(2000 ), create_date DATE );
在线重定义 生产环境执行建议
阶段
建议时段
关键监控指标
风险等级
启动重定义
非高峰
CPU、I/O利用率
中
同步数据
允许小并发
同步延迟、锁等待
高
FINISH切换
业务最低谷
锁持有时间
极高
通过分阶段执行并严格监控,可在 不影响在线业务 的前提下安全完成表结构变更。
在线重定义 1 2 3 4 5 6 7 8 9 10 BEGIN DBMS_REDEFINITION.START_REDEF_TABLE( uname = > USER , orig_table = > 'T' , int_table = > 'T_TEMP' , col_mapping = > 'id id, encrypt_name(name) name, create_date create_date' , options_flag = > DBMS_REDEFINITION.CONS_USE_PK ); END ;/
说明
关键参数
col_mapping
:定义字段映射,在此处调用加密函数。
CONS_USE_PK
:要求原表必须有主键,不支持无主键表。
重要检查
1 2 SELECT * FROM user_mview_logs WHERE master = 'T' ;
复制数据、依赖对象(索引、约束) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 DECLARE num_errors PLS_INTEGER; BEGIN DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS( uname = > USER , orig_table = > 'T' , int_table = > 'T_TEMP' , copy_indexes = > DBMS_REDEFINITION.CONS_ORIG_PARAMS, copy_triggers = > TRUE , copy_privileges = > TRUE , ignore_errors = > TRUE , num_errors = > num_errors ); DBMS_OUTPUT.PUT_LINE('依赖项错误数: ' || num_errors); END ;/
说明
增量同步数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 BEGIN DBMS_REDEFINITION.SYNC_INTERIM_TABLE( uname = > USER , orig_table = > 'T' , int_table = > 'T_TEMP' ); END ;/
说明
最终切换(原子操作) 1 2 3 4 5 6 7 8 BEGIN DBMS_REDEFINITION.FINISH_REDEF_TABLE( uname = > USER , orig_table = > 'T' , int_table = > 'T_TEMP' ); END ;/
说明
影响时间 :业务短时阻塞(<5秒) ,需获取排他锁。
锁监控
1 2 3 SELECT sid, type, lmode, request FROM v$lock WHERE id1 IN (SELECT object_id FROM dba_objects WHERE object_name = 'T' );
回退预案 :若此时失败,原表仍可正常访问。
验证与清理 验证操作
结构验证
数据校验
1 SELECT id, decrypt_name(name) AS plain_name FROM t WHERE ROWNUM <= 10 ;
依赖项检查
1 SELECT index_name, status FROM user_indexes WHERE table_name = 'T' ;
清理中间对象 1 2 DROP TABLE t_temp PURGE; EXEC DBMS_MVIEW.REFRESH('T_LOG' , 'C' );
参考文档 https://docs.oracle.com/cd/E11882_01/server.112/e25494/tables.htm#ADMIN11677
原文作者:
liups.com
原文链接:
http://liups.com/posts/8eeae1ab/
许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议