前几天见有客户咨询表列数据只让部分用户可见的访问控制问题,Oracle数据库在数据安全上的解决方案也是相当优秀的, 除了权限配置,还有加密与脱敏功能与组件,如列级TDE加密和Data masking对真实数据有修改,同时安全访问还有VPD、DV、 Data Redaction白皮书此类不修改原始数据。这里简单总结分享Data redaction功能特性。在EDB数据库发现同样实现了该功能。
Oracle Data Redaction 是Oracle数据库Oracle 12c中引入的新特性之一,也可以通过补丁集向后移植到11.2.0.4。该新特性是Advanced Security选项的一部分,支持对数据用户实时显示进行保护,而不需要对应用程序进行更改,在查询时直接反回启用data redaction的脱敏后的数据。
支持Redaction的方法有:
Full redaction. redact列数据的所有内容. 返回给查询应用程序用户的已脱敏值取决于列的数据类型。例如,NUMBER 数据类型的列使用零 (0) 进行密文,字符数据类型使用单个空格进行密文。
Partial redaction. 脱敏列数据的一部分。例如,您可以使用星号 (*) 编辑社会保险号,但最后 4 位数字除外。
Regular expressions.您可以使用正则表达式查找要密文的数据模式。例如,您可以使用正则表达式来密文电子邮件地址,这些地址可以具有不同的字符长度。它仅用于字符数据。
Random Redaction无论列中数据的数据类型如何,它都是每次调用数据时随机显示数据的方法。使用此方法调用数据时,数据编校会将数据更改为随机,因此数据看起来始终是唯一的。
在使用最常用的随机编辑中有一些重要的细节:
使用 Char 数据类型时,返回的数据长度将始终与列的字符数相同。例如,如果列为 CHAR (25),则输出结果将提供 25 个随机字符的字符串。
使用 VARCHAR2 数据类型时,返回的数据长度是列中的字符数。例如,如果数据类型为 VARCHAR (25) 的列包含 10 个字符的数据,则数据编校的结果为 10 个随机字符。
在number数据类型中,随机返回正数。
在日期时间数据类型中,显示随机日期。
No redaction. T使用“No redaction”选项可以测试Redaction策略的内部操作,而不会影响针对定义了策略的表的查询结果。您可以使用此选项在将密文策略定义应用于生产环境之前对其进行测试。

它如何工作的?
何时使用 Oracle 数据编校?
1. 当您必须伪装应用程序和应用用户必须访问的敏感数据时,请使用 Oracle 数据编校。
2. 数据编校使您能够使用几种不同的密文样式轻松伪装数据。
3. Oracle 数据编校非常适合您必须从返回给某些应用程序用户的个人身份信息 (PII) 查询结果集中编辑特定字符的情况。例如,您可能希望将以数字 4320 结尾的社会保险号显示为 ***-**-4320。
它支持以下列数据类型:
如何检查编校策略?
select * from redaction_policies;
我们需要确保相应的用户(在我的例子中是应用程序用户)有权限访问DBMS_REDACT包。
GRANT EXECUTE ON sys.dbms_redact TO apps;
如果查询用户具有EXEMPT REDACTION POLICY system privilege,redaction will not be performed。如果用户没有EXEMPT REDACTION POLICY系统权限,则将在当前用户的环境中评估策略表达式。如果策略表达式的计算结果为EXEMPT REDACTION POLICYTRUE ,则将执行编校,否则不会执行编校。
您需要包的权限EXECUTE privilege on the DBMS_REDACT才能执行其子程序。界面中的过程以当前用户的权限执行。更多
性能影响
高速性能对于Data Redaction至关重要,因为目标数据库通常是生产系统。数据需要在运行时动态转换,而不改变存储在磁盘或缓存和缓冲区中的数据。因为转换将在生产中执行环境频繁重复执行,性能开销必须小。Data Redaction利用了Oracle数据库的性能优化,这只有作为数据库内核的一部分才有可能实现。该实现确保了数据转换在内存中进行快速计算。策略信息缓存在内存中,每次执行只计算一次策略表达式,因此不影响每一行的性能。
Oracle Database的访问控制的特性
| Data Redaction | Virtual Private Database | Database Vault | |
| 功能概要 | 列的访问控制 &Redaction | 行・列的访问控制 | 表的访问控制 特权用户管理 |
| 必要许可证 | Advanced Security Option | Enterprise Edition | Database Vault Option |
| 版本 | (11.2.0.4 with patch)12c~ | 8i~(Column 从10gR1) | 10gR2~ |
| 对象访问 | 列(SELECT) | 列・行(DML) | 对象・SQL命令 |
| 说明 | 根据表中定义的Redaction对策的条件,不在列中展示,或者Redaction到任意值 | 根据表中定义的VPD对策的条件,自动追加WHERE语句,不表示出行。这时还可以将特定的列表示为NULL | 使用Realm、规则、命令规则等各种要素,访问对象(表、视图以及PL/SQL等),可以控制,并强制访问AQL命令自身的执行 |
| 特权用户 | 对策不适用 | 对策不适用 | 对任何用户都适用对策 |
| 设定 | DBMS_REDACTpackage或者、Oracle Enterprise Manager | DBMS_RLSpackage或者、Oracle Enterprise Manager | DVSYS.DBMS_MACADMpackage或者、Oracle Enterprise Manager |
在 Oracle Data Redaction and Oracle Data masking 有什么不同?
| Oracle Data Masking | Oracle Data Redaction | |
| 安装方法 | Oracle Enterprise Manager | DBMS_REDACTpackage或者、Oracle Enterprise Manager |
| 目的 | 直接对表masking,正式变成相近的测试数据 | 根据用户权限不同Redaction表以及视图的访问控制 |
| 执行时机 | online 创建表、数据拷贝后,执行masking | online实时理解查询结果执行mask处理 |
| 存储数据的影响 | 永久变更数据 | 没有影响 |
在 Oracle Data Redaction and Oracle Virtual Pricate Database有什么不同?
- 虽然您可以使用 Oracle Data Redaction更实用地编辑数据,但 Oracle Virtual Private Database将数据返回为 NULL。当值返回 NULL 时,可能会导致应用程序出现问题。使用 Oracle Data Redaction,您将不会遇到此类问题。
- Oracle Virtual Private Database对静态和动态内容很敏感。Data Redaction 仅对静态内容敏感。
- Data Redaction 只允许在表或视图上定义一个策略,而 Oracle Virtual Private Database允许您定义多个策略。
Oracle Data Redaction 对SYS and SYSTEM or default schemas有什么影响?
- EXP_FULL_DATABASE and IMP_FULL_DATABASE 、DBA roles included in it (EXEMPT REDACTION POLICY)
- 默认情况下,SYS and SYSTEM 具有“EXEMPT REDACTION POLICY”权限。此权限意味着 Oracle Data Redaction policy 对这些用户无效。换句话说,除非另有说明,否则它们始终可以读取数据。
- 默认情况下,创建的用户没有“EXEMPT REDACTION POLICY”权限。例如,HR 用户直接受此情况的影响。
- 不应撤销 SYS 和 SYSTEM 等用户的“EXEMPT REDACTION POLICY ”角色。
- EXP_FULL_DATABASE和IMP_FULL_DATABASE 、DBA角色都默认包含EXEMPT REDACTION POLICY权限。
DEMO
sqlplus / as sysdba
SQL> create table anbob.testdm(id int,name varchar2(20), tel varchar2(20),card varchar2(30));
SQL> insert into anbob.testdm values(1,'anbob','13800000001','111-222-333-444');
SQL> insert into anbob.testdm values(2,'weejar','13900000001','777-222-333-444') ;
SQL> commit;
SQL> select * from anbob.testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob 13800000001 111-222-333-444 18
2 weejar 13900000001 777-222-333-444 18
SQL> grant execute on sys.dbms_redact to anbob;
Grant succeeded.
[oracle@oel7db1 ~]$ sqlplus anbob/oracle@cdb1pdb1
SQL> select * from session_roles;
no rows selected
SQL> BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'ANBOB',
object_name => 'TESTDM',
column_name => 'CARD',
policy_name => 'REDACT_CARD',
function_type => DBMS_REDACT.PARTIAL,
function_parameters =>'VVVFVVVFVVVFVVV,VVV-VVV-VVV-VVV,*,1,6',
expression => '1=1');
END;
/
SQL> select * from testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob 13800000001 ***-***-333-444 18
2 weejar 13900000001 ***-***-333-444 18
-- 修改
SQL> create user weejar identified by oracle;
SQL> grant select any table to weejar;
SQL> grant create session to weejar;
BEGIN
DBMS_REDACT.alter_policy(
object_schema => 'ANBOB',
object_name => 'TESTDM',
column_name => 'CARD',
policy_name => 'REDACT_CARD',
action=>DBMS_REDACT.modify_expression,
expression=>'SYS_CONTEXT(''USERENV'',''SESSION_USER'') != ''WEEJAR''');
9 END;
10 /
PL/SQL procedure successfully completed.
[oracle@oel7db1 ~]$ sqlplus weejar/oracle@cdb1pdb1
SQL> select * from anbob.testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob 13800000001 111-222-333-444 18
2 weejar 13900000001 777-222-333-444 18
[oracle@oel7db1 ~]$ sqlplus anbob/oracle@cdb1pdb1
SQL> select * from testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob 13800000001 ***-***-333-444 18
2 weejar 13900000001 ***-***-333-444 18
-- 增加列
BEGIN
DBMS_REDACT.alter_policy(
object_schema => 'ANBOB',
object_name => 'TESTDM',
policy_name => 'REDACT_CARD',
column_name => 'TEL',
ACTION=>DBMS_REDACT.ADD_COLUMN
);
9 END;
10 /
PL/SQL procedure successfully completed.
SQL> select * from testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob ***-***-333-444 18
2 weejar ***-***-333-444 18
BEGIN
DBMS_REDACT.alter_policy(
object_schema => 'ANBOB',
object_name => 'TESTDM',
policy_name => 'REDACT_CARD',
column_name => 'AGE',
ACTION=>DBMS_REDACT.ADD_COLUMN,
function_type => DBMS_REDACT.RANDOM
);
10 END;
11 /
PL/SQL procedure successfully completed.
SQL> select * from testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob ***-***-333-444 16
2 weejar ***-***-333-444 15
SQL> select * from testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob ***-***-333-444 17
2 weejar ***-***-333-444 7
-- 检查存在的data redaction
SQL> select * from redaction_policies
2 ;
OBJECT_OWNER OBJECT_NAME POLICY_NAME EXPRESSION ENA POLICY_DESCRIPTION
-------------------- ------------------------------ ------------------------------ ------------------------------ --- ------------------------------
ANBOB TESTDM REDACT_CARD SYS_CONTEXT('USERENV','SESSION YES
_USER') != 'WEEJAR'
SQL> select object_owner,object_name,column_name,function_type,function_parameters from REDACTION_COLUMNS;
OBJECT_OWNER OBJECT_NAME COLUMN_NAME FUNCTION_TYPE FUNCTION_PARAMETERS
-------------------- ------------------------------ -------------------- --------------------------- --------------------
ANBOB TESTDM AGE RANDOM REDACTION
ANBOB TESTDM CARD PARTIAL REDACTION VVVFVVVFVVVFVVV,VVV-
VVV-VVV-VVV,*,1,6
ANBOB TESTDM TEL FULL REDACTION
-- 同一个表上只允许1个policy
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'ANBOB',
object_name => 'TESTDM',
column_name => 'AGE',
policy_name => 'REDACT_AGE',
function_type => DBMS_REDACT.FULL,
expression => '1=1',
ENABLE=>true);
10 END;
11 /
BEGIN
*
ERROR at line 1:
ORA-28069: A data redaction policy already exists on this object.
ORA-06512: at "SYS.DBMS_REDACT_INT", line 3
ORA-06512: at "SYS.DBMS_REDACT", line 21
ORA-06512: at line 2
SQL> select card,count(*) from testdm group by card;
CARD COUNT(*)
------------------------------ ----------
***-***-333-444 1
***-***-333-444 1
SQL> select distinct card from testdm;
CARD
------------------------------
***-***-333-444
SQL> create table testdm1 as select * from testdm;
create table testdm1 as select * from testdm
*
ERROR at line 1:
ORA-28081: Insufficient privileges - the command references a redacted object.
SQL> select * from testdm where card like '7%';
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
2 weejar 13900000001 ***-***-333-444 18
--删除
begin
DBMS_REDACT.DROP_POLICY(
object_schema => 'ANBOB',
object_name => 'TESTDM',
policy_name => 'REDACT_CARD');
end;
7 /
PL/SQL procedure successfully completed.
SQL> select * from testdm;
ID NAME TEL CARD AGE
---------- -------------------- -------------------- ------------------------------ ----------
1 anbob 13800000001 111-222-333-444 18
2 weejar 13900000001 777-222-333-444 18
网上有个文档 Oracle Data Redaction is Broken 显示data broken可以绕过,也许是19c前的版本,本测试环境19.3, 验证一下那些方法是否可用?
第一种方法使用带有INSERT、UPDATE和DELETE的returns INTO子句
SET SERVEROUTPUT ON
DECLARE
buffer varchar(30);
BEGIN
UPDATE testdm
SET id = id
WHERE id = 1
RETURNING card INTO buffer;
DBMS_OUTPUT.put_line('Card=' || buffer);
9 END;
10 /
Card=***-***-333-444
第二种方法使用xmlquery
SQL> select xmlquery('for $i in ora:view("testdm") return $i' returning content) from dual;
select xmlquery('for $i in ora:view("testdm") return $i' returning content) from dual
*
ERROR at line 1:
ORA-28093: operation on column "CARD" is not supported by data redaction
Note:
显然在oracle 19c中data redaction运行正常,无法绕过。