Oracle Data Redaction(数据脱敏)

Oracle Data Redaction(数据脱敏)

适用版本:Oracle Database 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

Oracle Data Redaction(数据脱敏) 是 12c 引入的特性[1],对查询结果实时脱敏:

核心特性

  • 应用透明:无需修改应用
  • 实时脱敏:查询时脱敏
  • 基于策略:用户/时间/IP 等条件
  • 多种脱敏方式:完全/部分/正则/随机

典型场景

  • 客服查看用户信息
  • 应用日志脱敏
  • 测试数据脱敏

2. 脱敏策略类型

2.1 完全脱敏(Full Redaction)

-- 数字返回 0
-- 字符返回空格
-- 日期返回 01-JAN-01

2.2 部分脱敏(Partial Redaction)

-- 信用卡号: ****-****-****-1234
-- 身份证号: 110***********1234

2.3 正则脱敏(Regular Expression)

-- 邮箱: a***@example.com
-- 电话: 138****1234

2.4 随机脱敏(Random)

-- 每次返回不同的随机值

3. 配置完全脱敏

3.1 创建策略

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'employees',
    policy_name => 'redact_ssn',
    column_name => 'ssn',
    function_type => DBMS_REDACT.FULL,
    expression => '1=1'
  );
END;
/

3.2 测试

-- 原始数据
SELECT ssn FROM scott.employees WHERE id = 1;
-- 返回: ' ' (空格)

-- 普通用户看到的
SELECT ssn FROM scott.employees;
-- 所有 ssn 都是空格

-- SYS 用户看到的
SELECT ssn FROM scott.employees;
-- 真实数据(SYS 绕过脱敏)

4. 配置部分脱敏

4.1 信用卡号脱敏

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_credit_card',
    column_name => 'credit_card',
    function_type => DBMS_REDACT.PARTIAL,
    function_parameters => 'VVVVFVVVVFVVVVFVVVV,VVVV-VVVV-VVVV-VVVV,*,1,12',
    expression => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') != ''APP_ADMIN'''
  );
END;
/

4.2 参数说明

function_parameters: 'input_format,output_format,mask_char,start_pos,end_pos'
- input_format: 输入格式(V=字符,F=固定分隔符)
- output_format: 输出格式
- mask_char: 脱敏字符
- start_pos: 脱敏起始位置
- end_pos: 脱敏结束位置

4.3 身份证号脱敏

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_id',
    column_name => 'id_card',
    function_type => DBMS_REDACT.PARTIAL,
    function_parameters => 'VVVVVVVVVVVVVVVVVVV,*,1,6,14',
    expression => '1=1'
  );
END;
/

5. 正则脱敏

5.1 邮箱脱敏

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_email',
    column_name => 'email',
    function_type => DBMS_REDACT.REGEXP,
    function_parameters => 'REGEXP_REPLACE(email, ''([^@]+)@(.*)'', ''\1****@\2'')',
    expression => '1=1'
  );
END;
/

5.2 电话号码脱敏

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_phone',
    column_name => 'phone',
    function_type => DBMS_REDACT.REGEXP,
    function_parameters => 'REGEXP_REPLACE(phone, ''(\d{3})\d{4}(\d{4})'', ''\1****\2'')',
    expression => '1=1'
  );
END;
/

6. 随机脱敏

6.1 数字随机

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'employees',
    policy_name => 'redact_salary',
    column_name => 'salary',
    function_type => DBMS_REDACT.RANDOM,
    expression => '1=1'
  );
END;
/

6.2 字符随机

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'employees',
    policy_name => 'redact_name',
    column_name => 'name',
    function_type => DBMS_REDACT.RANDOM,
    expression => '1=1'
  );
END;
/

7. 多列脱敏

7.1 一个策略多列

BEGIN
  DBMS_REDACT.ADD_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_all',
    column_name => 'ssn',
    function_type => DBMS_REDACT.FULL,
    expression => '1=1'
  );
  
  -- 添加更多列
  DBMS_REDACT.ALTER_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_all',
    action => DBMS_REDACT.ADD_COLUMN,
    column_name => 'credit_card',
    function_type => DBMS_REDACT.PARTIAL,
    function_parameters => 'VVVVFVVVVFVVVVFVVVV,VVVV-VVVV-VVVV-VVVV,*,1,12'
  );
  
  DBMS_REDACT.ALTER_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_all',
    action => DBMS_REDACT.ADD_COLUMN,
    column_name => 'email',
    function_type => DBMS_REDACT.REGEXP,
    function_parameters => 'REGEXP_REPLACE(email, ''([^@]+)@(.*)'', ''\1****@\2'')'
  );
END;
/

8. 策略条件

8.1 基于用户

expression => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') IN (''APP_USER'',''GUEST'')'

8.2 基于 IP

expression => 'SYS_CONTEXT(''USERENV'',''IP_ADDRESS'') NOT IN (''192.168.1.100'')'

8.3 基于时间

expression => 'TO_CHAR(SYSDATE, ''HH24'') BETWEEN ''18'' AND ''23'''

8.4 组合条件

expression => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') = ''APP_USER'' AND SYS_CONTEXT(''USERENV'',''IP_ADDRESS'') NOT IN (''192.168.1.100'')'

9. 策略管理

9.1 查看策略

SELECT 
  object_owner,
  object_name,
  policy_name,
  column_name,
  function_type,
  expression
FROM dba_redaction_policies;

9.2 启用/禁用

-- 禁用
BEGIN
  DBMS_REDACT.DISABLE_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_credit_card'
  );
END;
/

-- 启用
BEGIN
  DBMS_REDACT.ENABLE_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_credit_card'
  );
END;
/

9.3 修改策略

BEGIN
  DBMS_REDACT.ALTER_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_credit_card',
    action => DBMS_REDACT.MODIFY_EXPRESSION,
    expression => '1=1'
  );
END;
/

9.4 删除策略

BEGIN
  DBMS_REDACT.DROP_POLICY(
    object_schema => 'scott',
    object_name => 'customers',
    policy_name => 'redact_credit_card'
  );
END;
/

10. 监控与审计

10.1 审计脱敏操作

-- 审计 Data Redaction 策略变更
AUDIT ALTER ANY REDACTION POLICY BY ACCESS;
AUDIT CREATE REDACTION POLICY BY ACCESS;
AUDIT DROP ANY REDACTION POLICY BY ACCESS;

10.2 查看审计

SELECT 
  timestamp,
  username,
  action_name,
  obj_name
FROM dba_audit_trail
WHERE action_name LIKE '%REDACTION%'
ORDER BY timestamp DESC;

11. 常见坑与排错

11.1 脱敏不生效

修复

-- 1. 检查策略
SELECT * FROM dba_redaction_policies;

-- 2. 检查条件
SELECT expression FROM dba_redaction_policies WHERE policy_name='REDACT_CREDIT_CARD';

-- 3. 验证条件
SELECT 1 FROM dual WHERE <expression>;

11.2 ORA-28081: 权限不足

修复

-- 需要 REDACTION_ADMIN_ROLE
GRANT REDACTION_ADMIN_ROLE TO admin_user;

11.3 SYS 用户绕过脱敏

原因:SYS/SYSDBA 默认绕过脱敏。

修复

-- 1. 不使用 SYS 查看业务数据
-- 2. 或启用 EXEMPT REDACTION POLICY 审计
AUDIT EXEMPT REDACTION POLICY BY ACCESS;

11.4 脱敏影响索引

修复

-- 脱敏列上的索引仍可用于过滤
-- 但返回结果是脱敏后的

-- 建议在 WHERE 条件使用真实值
SELECT * FROM customers WHERE credit_card = '1234567890123456';
-- WHERE 用真实值,SELECT 返回脱敏值

11.5 DML 失败

原因:脱敏策略可能影响 INSERT/UPDATE。

修复

-- 确保策略仅针对 SELECT
-- 或在应用层处理

12. 最佳实践

  1. 敏感数据脱敏:身份证、信用卡、薪资
  2. 基于用户条件:仅特定用户脱敏
  3. 使用部分脱敏:保留部分可识别信息
  4. 正则脱敏:复杂格式(邮箱、电话)
  5. SYS 不访问业务数据:绕过脱敏
  6. 脱敏策略审计:监控变更
  7. PDB 独立策略:多租户隔离
  8. 结合 VPD:行级+列级防护
  9. 测试验证:确保脱敏生效
  10. 应用层配合:避免脱敏影响功能

13. 参考资料

[1] Oracle Database Advanced Security Guide 19c, “Data Redaction” https://docs.oracle.com/en/database/oracle/oracle-database/19/asoag/data-redaction.html

[2] Oracle Database Security Guide 19c, “Managing Data Redaction” https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/