数据脱敏
背景
由于敏感数据是数据库安全中重要的一部分,因此对于敏感数据的脱敏是
很有必要的。GBase 8a MPP Cluster提供动态数据脱敏功能供不同用户使用, 以满足不同需求。
使得开发人员或者数据库管理员能够有效控制数据库中敏感数据的暴露程 度,并且在数据库层面生成脱敏数据,大大简化了业务应用层的安全设计和编 码。
使得用户可以通过SQL语法的形式,给需要进行数据脱敏的字段添加脱敏 属性,并通过用户权限控制,决定是否对有查询要求的用户暴露原始数据。
脱敏功能
动态数据脱敏并不会真正改动表中存储的实际数据,只是在查询的时候应 用该特性控制查询返回的数据。
动态数据脱敏是否启用受当前用户权限影响,super用户和拥有unmask权 限的用户不受脱敏规则影响可以访问实际数据,没有unmask权限的用户受脱敏 规则影响只能访问到脱敏后的数据。
脱敏只对投影列有效。
MASKED WITH(FUNCTION = 'TYPE (参数)')
动态数据脱敏支持四种类型数据脱敏函数,如下:
1) 默认脱敏default类型。
这种类型没有参数。
MASKED WITH(FUNCTION = 'DEFAULT。')
2) 随机脱敏random类型。
random(min,max)有两个参数标定随机范围,参数min的最小值为1,参数 max的最大值为1。。。
MASKED WITH(FUNCTION = 'RANDOMd, 100)')
3) 自定义脱敏partial类型。
这种类型包含三个参数,partial (prefix, padding, suffix),参数详细
说明如下:
• prefix表示前缀保留显示字符数量;
• padding表示脱敏显示字符;
• suffix表示结尾保留显示字符数量。
MASKED WITH(FUNCTION = 'PARTIAL(1,'XXXX',1)')
4) 哈希脱敏sha类型。
这个类型没有参数。
MASKED WITH(FUNCTION = 'SHA()')
5) 自定义脱敏keymask类型。
keymask(substr,padding, pos)
masked with(function=' keymask(〃@gbase〃,〃****〃,0)')
函数介绍
默认脱敏函数
1. 若数据类型包含date、datetime和time。
• date 会以 “1900-01-01 ”显示;
• datetime 会以 “1900-01-01 00:00:00” 显示;
• time 会以 “00:00:00” 显示。
2. 若数据类型是整型、浮点型和decimal。
• 整型和浮点型会显示0;
• decimal会显示为0.000...,带有结果小数位(定义的类型或者评估的 类型)个数0。
3. 若数据类型是字符串类型的。将会替换为固定4个X字符"xxxx”。
4. NULL值。不做脱敏处理,显示为NULL。
5. SQL函数。如果SQL函数的任一参数含有脱敏属性,则按照函数返 同结果类型,执行默认脱敏。
示例
gbase> CREATE TABLE t_m_default(name VARCHAR(10) MASKED
WITH(FUNCTION = 'DEFAULT()'),b_date DATETIME MASKED
WITH(FUNCTION = 'DEFAULT()'),age INT MASKED WITH(FUNCTION ='DEFAULT0'));
Query OK, 0 rows affected (Elapsed: 00:00:00.53)
gbase> INSERT INTO t_m_default VALUES('Jone smith','1989-03-04 12:31:24.123000',29);
Query OK, 1 row affected (Elapsed: 00:00:00.12)
gbase> SELECT * FROM t_m_default;
+ + + +
| name | b_date | age |
+ + + +
| xxxx | 1900-01-01 00:00:00 | 0 |
+ + + +
1 row in set (Elapsed: 00:00:00.09)
脱敏前
姓名(varchar) 出生日期(datetime) 年龄(int)
Jone smith 1989-03-04 12:31:24.123000 29
脱敏后
姓名(varchar) 出生日期(datetime) 年龄(int)
xxxx 1900-01-01 00:00:00 0
随机脱敏
它会将数字随机显示成指定范围内的值,若多次执行,同一行的随机值会 不同。假设先设置脱敏范围为(1, 4):
gbase> CREATE TABLE t_m_random(age INT MASKED
WITH(FUNCTION = 'RANDOM(1,4)'));
Query OK, 0 rows affected (Elapsed: 00:00:00.09)
gbase> INSERT INTO t_m_random VALUES(29),(19);
Query OK, 2 rows affected (Elapsed: 00:00:00.07)
Records: 2 Duplicates: 0 Warnings: 0
gbase> SELECT * FROM t_m_random;
+ +
I age I
+ +
I 4 I
1 3 I
+ +
2 rows in set (Elapsed: 00:00:00.03)
脱敏前数据
年龄(int)
29
19
应用随机脱敏后结果
年龄(int)
4
3
△注意
NULL值不做脱敏处理,显示仍为NULL。
自定义脱敏
设定 prefix 为 3, suffix 为 6, padding 字符 "XXXX”。
gbase> CREATE TABLE t_m_partial(context VARCHAR(255) MASKED
WITH(FUNCTION = 'PARTIAL(3,"XXXX",6)'));
Query OK, 0 rows affected (Elapsed: 00:00:00.24)
gbase> INSERT INTO t_m_partial VALUES('This is a book on the desk'),('Hello');
Query OK, 2 rows affected (Elapsed: 00:00:00.08)
Records: 2 Duplicates: 0 Warnings: 0
gbase> SELECT * FROM t_m_partial;
+ +
| context |
+ +
| ThiXXXX desk. |
|XXXX |
+ +
2 rows in set (Elapsed: 00:00:00.02)
脱敏前数据
内容(varchar(255))
This is a book on the desk.
Hello
应用自定义脱敏后结果
内容(varchar(255))
ThiXXXX desk.
XXXX
八'注意
NULL值不做脱敏处理,显示为NULL。
SHA 脱敏
gbase> CREATE TABLE t_m_sha(context VARCHAR(255) MASKED WITH(FUNCTION
='SHAO'));
Query OK, 0 rows affected (Elapsed: 00:00:00.08)
gbase> INSERT INTO t_m_sha VALUES('abc');
Query OK, 1 row affected (Elapsed: 00:00:00.10)
gbase> SELECT * FROM t_m_sha;
+ +
| context |
+ +
|a9993e364706816aba3e25717850c26c9cd0d89d |
+ +
1 row in set (Elapsed: 00:00:00.03)
脱敏前数据
内容(varchar(255))
abc
应用SHA脱敏后显示结果
内容(varchar(255))
内容(varchar(255))
“a9993e364706816aba3e25717850c26c9cd0d89d”
△注意
NULL值不做脱敏处理,仍显示为NULL。
相关属性
建表,只需要有create权限:
create table t1(a int masked with(function= 'default。'));
create table t2(a varchar(255) masked with(function= 'sha()'));
create table t3(a int masked with(function= 'random(1,10) '));
create table t4(a varchar(255) masked with(function= 'partial(2,"XXX", 3)'));
说明:create table like 继承 mask 属性。
Alter可以添加和修改mask属性,mask的语法内容同建表,需要同时拥有 alter 和 unmask 权限。
Alter table t1 alter a masked with(function= 'sha()');
显示mask属性。
Show create table <tablename>;
例如:
gbase> show create table t4;
+ +
+
| Table | Create Table
I
+ +
+
| t4 | CREATE TABLE "t4"(
"a" varchar(255) DEFAULT NULL MASKED WITH(FUNCTION='DEFAULT()')
)ENGINE二EXPRESS DEFAULT CHARSET二utf8 TABLESPACE='sys_tablespace' |
删除mask属性。
Alter table 表名 alter 列名 drop masked;
超级用户或其他拥有unmask权限的用户可以查看原始未脱敏数据。
grant unmask on *.* to user;
例如:
create user user2;
grant unmask on *.* to user2;
show grants for user2;
结果:
+ +
| Grants for user2@% |
+ +
| GRANT UNMASK ON *.* TO 'user2'@'%' |
+ +
1 row in set (Elapsed: 00:00:00.00)
投影列函数脱敏说明
脱敏规则
1、控制流函数可以直接返回脱敏列,而非对脱敏列进行比较和计算,这时 函数会将脱敏列的脱敏规则应用到其他返回值。这类函数有case when/decode、if、ifhull、nvl 和 coalesce 函数。举例如下:
select case col when 1 then '123' when 2 then '456' when 3 then mask_col else '789' from t; 说明:其中col为非脱敏列,mask_col为脱敏列,“123”、“456”、“789”为 常量。
上面查询中case when函数可能的返回值为'123'、’456'、'789'和mask_col, 返回值中包含了脱敏列,这时会对常量'123'、'456'和'789'按照脱敏列 mask_col的脱敏规则进行脱敏。
• 当这类函数的返回值中有多个脱敏列(不同列)时,该函数将使用默认 脱敏规则(不考虑多列脱敏规则是否完全相同)。
比如:
select nvl(mask_col1, mask_col2) from t;
nvl函数将使用默认脱敏规则。
而
select nvl(mask_col1, mask_col1) from t;
nvl函数仍将使用mask_col1的脱敏规则。
• 当这类函数的返回值中既包含脱敏列,同时也包含非脱敏列(不是常量) 时,该函数也将使用默认脱敏规则。
比如:
select coalesce(col, mask_col) from t;
coalesce函数将使用默认脱敏规则。
• 当这类函数的返回值中类型不完全相同时,将会依据数据类型的转换规 则进行转换,如果转换后的数据类型与脱敏列的原始类型不一致(只考 虑string、real、decimal和int四个级别,而不考虑更细的数据类型), 则使用默认脱敏。
比如:
select coalesce(mask_int_col, 'abcdef) from t;
coalesce函数返回值为string,与mask_int_col的类型(int)不一致,所以coalesce 将使用默认脱敏。
默认脱敏时,并不是将mask_int_col的值转换为string,而是直接返回string 类型的默认脱敏值(xxxx)。
控制流函数类型转换规则:
,任何一个参数为string时,则按string进行运算;
-没有string时,如果存在real,按real进行运算;
,没有string和real时,如果存在decimal,按decimal进行运算;
-日期时间类型算作string类型。
控制流函数只对所有可能的返回值进行脱敏,对控制逻辑中的其他参数不脱 敏,比如case when函数中只对then和else进行脱敏,对case和when分支中 的参数不脱敏。
• Union, Intersect和Minus运算时,对应列的脱敏规则选取与控制流函 数的脱敏规则一致。
比如:
select mask_int_col from t union select mask_int_col as col from t;
将使用mask_int_col的脱敏规则,而:
select mask_int_col from t union select mask_int_col+1 from t;
将使用默认脱敏。
2、绝大部分函数是对参数进行比较或者计算,比如一些字符串函数、比较函 数、数值函数、时间和日期函数、OLAP函数和聚集函数等,这类函数的参数 如果有脱敏列,函数将使用默认脱敏规则对返回值进行脱敏,而非对脱敏列脱 敏后参与运算。
举例如下:
select concat(mask_col, '123') from t;
其中mask_col为脱敏列,'123'为常量。
上面查询中concat函数并非将脱敏后的mask_col字符串连接常量'123',而是 对concat返回值进行默认脱敏。由于concat返回值是字符类型,所以上述结 果除mask_col为NULL的情况外(NULL值情况返回值为NULL),始终返 同‘XXXx'o
再比如select mask_col > 1 from t;将依据函数的返回值类型使用默认脱 敏规则,所以除mask_col为NULL值外,始终返回0。
脱敏列脱敏后如果超过脱敏列的最大长度,则自动截断为脱敏列的最大长度。
比如脱敏列定义为:
mask_col varchar(5) masked with (function ='partial(2,"xxxx",2)')
则值“abcde”理论上应脱敏为“abxxxxde”,脱敏后的长度超过了最大长度5, 自动截断为“abxxx”。
同样,对于一些可设置长度的函数脱敏时也会被截断,比如:
select left(mask_col, 2) from t;
left函数将使用默认脱敏,理论上应脱敏为“xxxx”,但超过了 left函数设置 的最大长度,所以自动截断为“XX”。
脱敏规则继承
这种传递也只限于非比较计算类的函数。
举例如下:
select case col when 1 then nvl(mask_col, '123') when 2 then '456' else '789' from t; 说明:其中col为非脱敏列。mask_col为脱敏列,“123”、“456”、“789”为常 量。
上面查询中,nvl函数可能的返回值有mask_col和'123',所以nvl函数使用 mask_col的脱敏规则对mask_col和'123'脱敏,此脱敏规则同时也传递到外层 case when函数中,所以'456'和'789'也会使用mask_col的脱敏规则脱敏。
2、 脱敏规则继承还出现在子查询的使用场景中,外层投影列的脱敏规则继承 自子查询投影列的脱敏规则。
举例如下:
select col from (select reverse(mask_col) as col from t3) as tmp;
其中mask_col为脱敏列。
上面查询中,reverse函数会对参数进行比较或运算操作,当参数为脱敏列时, 函数的脱敏规则为默认脱敏。外层的col脱敏规则继承自子查询 reverse(mask_col)的脱敏规则,所以外层的col脱敏规则也为默认脱敏。
场景示例
create table t (i1 int,
vc1 varchar(10) masked with (function='partial(2,"*****",0)'),
vc2 varchar(10) masked with (function='partial(2,"*****",0)'));
insert into t values (1, 'nblknabpa', 'pombkaia');
insert into t values (2, '.mapkna', '0jbadflk');
insert into t values ();
示例1 :第i类函数case when脱敏列规则;
gbase>select case i1 when 1 then vc1 when 2 then ' 12345' else '67890' end as res from t;
+ +
| res |
+ +
| nb***** |
| 12***** |
| 67***** |
+ +
示例2:第i类函数coalesce脱敏列规则;
gbase>select coalesce(vcl,' 12345') as res from t;
+ +
| res |
+ +
| nb***** |
| .m***** |
| 12***** |
+ +
示例3:第i类函数case when多脱敏列默认脱敏;
gbase> select case i1 when 1 then vc1 when 2 then vc2 else ' 67890' end as res from
t;
+ +
| res |
+ +
| xxxx |
| xxxx |
| xxxx |
+ +
示例4:第ii类函数substring默认脱敏;
gbase> select substring(vc1, 1, 2) as res from t;
+ +
| res |
+ +
| xx |
| xx |
| NULL |
+ +
示例5:第ii类函数concat默认脱敏;
gbase> select concat(vcl,' 123') as res from t;
+ +
| res |
+ +
| xxxx |
| xxxx |
| NULL |
+ +
示例6:第i类函数嵌套使用;
gbase> select case when i1 > 1 then coalesce (vcl, ' 12345') else ' 67890' end as res from t;
+ +
| res |
+ +
| 67***** |
| .m***** |
| 67***** |
+ +
示例7:第ii类函数嵌套使用;
gbase> select concat(substring(vc1,1,2),' 123') as res from t;
+ +
| res |
+ +
| xxxx |
| xxxx |
| NULL |
+ +
示例8:第i类和ii类函数混合嵌套调用;
gbase> select coalesce(substring(vcl, 1,2),' 12345') as res from t;
(或者 select substring (coalesce (vc1, ' 12345'), 1, 2) as res from t;)
+ +
| res |
+ +
| xxxx |
| xxxx |
| xxxx |
+ +
示例9: 子查询内或外调用1类;
gbase> select res from (select coalesce(vc1,' 12345' )as res from t) as tmp;
(或者 select coalesce(vc1, ' 12345') as res from (select vc1 from t) as tmp;)
+ +
| res |
+ +
| nb***** |
| .m***** |
| 12***** |
+ +
示例10:子查询内或外调用11类;
gbase> select res from (select concat(vc1,' 123') as res from t) as tmp;
(或者 select concat (vc1, ' 123') as res from (select vc1 from t) as tmp;)
+ +
| res |
+ +
| xxxx |
| xxxx |
| NULL |
+ +
示例11:子查询内外调用1类;
gbase> select case when i1 > 1 then resl else '67890' end as res from (select
il, coalesce(vcl, ' 12345') as res1 from t) as tmp;
+ +
| res |
+ +
| 67***** |
| .m***** |
| 67***** |
+ +
示例12:子查询内外调用11类;
gbase> select concat(res1,'123') as res from (select substring(vc1,1,2) as res1 from t) as tmp;
+ +
| res |
+ +
| xxxx |
| xxxx |
| NULL |
+ +
示例13:子查询内外混合调用1类和11类。
gbase> select substring(res1,1,4) as res from (select coalesce (vc1, ' 12345') as
res1 from t) as tmp;
(或者
gbase> select coalesce (res1, ' 12345') as res from (select substring(vc1,1,2) a s res1 from t) as tmp;)
+ +
| res |
+ +
| xxxx |
| xxxx |
| xxxx |
+-
说明:脱敏列脱敏后如果超过脱敏列的最大长度,则自动截断为脱敏列的最 大长度。
比如脱敏列定义为:
mask_col varchar(5) masked with (function ='partial(2,"xxxx",2)')
则值“abcde”理论上应脱敏为“abxxxxde”,脱敏后的长度超过了最大长度5,自 动截断为“abxxx”。
脱敏列脱敏后对于一些可设置长度的函数脱敏时也会被截断,比如:
select left(mask_col, 2) from t;
left函数将使用默认脱敏,理论上应脱敏为“xxxx”,但超过了 left函数设置的 最大长度,所以自动截断为“XX”。
Union、Intersect和Minus运算时,对应列的脱敏规则与控制流函数的脱敏规 则一致。
比如:
select mask_int_col from t union select mask_int_col as col from t;
将使用mask int col的脱敏规则,而:一
select mask_int_col from t union select mask_int_col+1 from t;
将使用默认脱敏。