乐趣区

关于GaussDB:数据脱敏数仓安全隐私保护见真招儿

摘要:如何增强技术层面的数据安全和隐衷爱护,对数据仓库产品自身提出更多的性能要求,也是数据安全建设最卓有成效的方法。

本文分享自华为云社区《GaussDB(DWS)平安:隐衷爱护现真招儿——数据脱敏》,原文作者:wo 华哒哒。

引言

大数据时代的到来,颠覆了传统业态的运作模式,激发出新的生产潜能。数据成为重要的生产因素,是信息的载体,数据间的流动也潜藏着更高阶维度的价值信息。对于数据控制者和数据处理者而言,如何最大化数据流动的价值,是数据挖掘的初衷和意义。然而,一系列信息泄露事件的曝光,使得数据安全越来越受到宽泛的关注。

各国各地区逐渐建立健全和欠缺数据安全与隐衷爱护相干法律法规,提供用户隐衷爱护的法律保障。如何增强技术层面的数据安全和隐衷爱护,对数据仓库产品自身提出更多的性能要求,也是数据安全建设最卓有成效的方法。

什么是数据脱敏?

数据脱敏(Data Masking),顾名思义,是屏蔽敏感数据,对某些敏感信息(比方,身份证号、手机号、卡号、客户姓名、客户地址、邮箱地址、薪资等等)通过脱敏规定进行数据的变形,实现隐衷数据的牢靠爱护。业界常见的脱敏规定有,替换、重排、加密、截断、掩码,用户也能够依据冀望的脱敏算法自定义脱敏规定。

通常,良好的数据脱敏施行,须要遵循如下两个准则,第一,尽可能地为脱敏后的利用,保留脱敏前的有意义信息;第二,最大水平地避免黑客进行破解。

数据脱敏分为静态数据脱敏和动态数据脱敏。静态数据脱敏,是数据的“搬移并仿真替换”,是将数据抽取进行脱敏解决后,下发给上游环节,随便取用和读写的,脱敏后数据与生产环境相隔离,满足业务需要的同时保障生产数据库的平安。动态数据脱敏,在拜访敏感数据的同时实时进行脱敏解决,能够为不同角色、不同权限、不同数据类型执行不同的脱敏计划,从而确保返回的数据可用而平安。

GaussDB (DWS)的数据脱敏性能,摒弃业务应用层脱敏依赖性高、代价大等痛点,将数据脱敏内化为数据库产品本身的平安能力,提供了一套残缺、平安、灵便、通明、敌对的数据脱敏解决方案,属于动态数据脱敏。用户辨认敏感字段后,基于指标字段,绑定内置脱敏函数,即可创立脱敏策略。脱敏策略(Redaction Policy)与表对象是一一对应的。一个脱敏策略蕴含表对象、失效条件、脱敏列 - 脱敏函数对三个要害因素,是该表对象上所有脱敏列的汇合,不同字段能够依据数据特色采纳不同的脱敏函数。当且仅当失效条件为真时,查问语句才会触发敏感数据的脱敏,而脱敏过程是内置在 SQL 引擎外部实现的,对生成环境用户是通明不可见的。

怎么用数据脱敏?

动态数据脱敏,是在查问语句执行过程中,依据失效条件是否满足,实现实时的脱敏解决。失效条件,通常是针对以后用户角色的判断。敏感数据的可见范畴,即是针对不同用户预设的。系统管理员,具备最高权限,任何时刻对任何表的任何字段都可见。确定受限制用户角色,是创立脱敏策略的第一步。

敏感信息依赖于理论业务场景和平安维度,以自然人为例,用户个体的敏感字段包含:姓名、身份证号、手机号、邮箱地址等等;在银行零碎,作为客户,可能还波及银行卡号、过期工夫、领取明码等等;在公司零碎,作为员工,可能还波及薪资、教育背景等;在医疗系统,作为患者,可能还波及就诊信息等等。所以,辨认和梳理具体业务场景的敏感字段,是创立脱敏策略的第二步。

产品内置一系列常见的脱敏函数接口,能够针对不同数据类型和数据特色,指定参数,从而达到不一样的脱敏成果。脱敏函数可采纳如下三种内置接口,同时反对自定义脱敏函数。三种内置脱敏函数可能涵盖大部分场景的脱敏成果,不举荐应用自定义脱敏函数。

  • MASK_NONE:不作脱敏解决,仅内部测试用。
  • MASK_FULL:全脱敏成固定值。
  • MASK_PARTIAL:应用指定的脱敏字符对脱敏范畴内的内容做局部脱敏。

不同脱敏列能够采纳不同的脱敏函数。比方,手机号通常显示后四位尾号,后面用 ”*” 替换;金额对立显示为固定值 0,等等。确定脱敏列须要绑定的脱敏函数,是创立脱敏策略的第三步。

以某公司员工表 emp,表的属主用户 alice 以及用户 matu、july 为例,简略介绍数据脱敏的应用过程。其中,表 emp 蕴含员工的姓名、手机号、邮箱、发薪卡号、薪资等隐衷数据,用户 alice 是人力资源经理,用户 matu 和 july 是一般职员。

假如表、用户及用户对表 emp 的查看权限均已就绪。

  • (1)创立脱敏策略 mask_emp,仅容许 alice 查看员工所有信息,matu 和 july 对发薪卡号、薪资均不可见。字段 card_no 是数值类型,采纳 MASK_FULL 全脱敏成固定值 0;字段 card_string 是字符类型,采纳 MASK_PARTIAL 按指定的输入输出格局对原始数据作局部脱敏;字段 salary 是数值类型,采纳数字 9 局部脱敏倒数第二位前的所有数位值。
postgres=# CREATE REDACTION POLICY mask_emp ON emp WHEN (current_user != 'alice')
ADD COLUMN card_no WITH mask_full(card_no),
ADD COLUMN card_string WITH mask_partial(card_string, 'VVVVFVVVVFVVVVFVVVV','VVVV-VVVV-VVVV-VVVV','#',1,12), 
ADD COLUMN salary WITH mask_partial(salary, '9', 1, length(salary) - 2);

切换到 matu 和 july,查看员工表 emp。

postgres=> SET ROLE matu PASSWORD 'Gauss@123';
postgres=> SELECT * FROM emp;
 id | name |  phone_no   | card_no |     card_string     |        email         |   salary   |      birthday       
----+------+-------------+---------+---------------------+----------------------+------------+---------------------
  1 | anny | 13420002340 |       0 | ####-####-####-1234 | smithWu@163.com      | 99999.9990 | 1999-10-02 00:00:00
  2 | bob  | 18299023211 |       0 | ####-####-####-3456 | 66allen_mm@qq.com    |  9999.9990 | 1989-12-12 00:00:00
  3 | cici | 15512231233 |         |                     | jonesishere@sina.com |            | 1992-11-06 00:00:00
(3 rows)
postgres=> SET ROLE july PASSWORD 'Gauss@123';
postgres=> SELECT * FROM emp;
 id | name |  phone_no   | card_no |     card_string     |        email         |   salary   |      birthday       
----+------+-------------+---------+---------------------+----------------------+------------+---------------------
  1 | anny | 13420002340 |       0 | ####-####-####-1234 | smithWu@163.com      | 99999.9990 | 1999-10-02 00:00:00
  2 | bob  | 18299023211 |       0 | ####-####-####-3456 | 66allen_mm@qq.com    |  9999.9990 | 1989-12-12 00:00:00
  3 | cici | 15512231233 |         |                     | jonesishere@sina.com |            | 1992-11-06 00:00:00
(3 rows)
  • (2)因为工作调整,matu 进入人力资源部参加公司招聘事宜,也对员工所有信息可见,批改策略失效条件。
postgres=> ALTER REDACTION POLICY mask_emp ON emp WHEN(current_user NOT IN ('alice', 'matu'));

切换到用户 matu 和 july,从新查看员工表 emp。

postgres=> SET ROLE matu PASSWORD 'Gauss@123';
postgres=> SELECT * FROM emp;
 id | name |  phone_no   |     card_no      |     card_string     |        email         |   salary   |      birthday       
----+------+-------------+------------------+---------------------+----------------------+------------+---------------------
  1 | anny | 13420002340 | 1234123412341234 | 1234-1234-1234-1234 | smithWu@163.com      | 10000.0000 | 1999-10-02 00:00:00
  2 | bob  | 18299023211 | 3456345634563456 | 3456-3456-3456-3456 | 66allen_mm@qq.com    |  9999.9900 | 1989-12-12 00:00:00
  3 | cici | 15512231233 |                  |                     | jonesishere@sina.com |            | 1992-11-06 00:00:00
(3 rows)
postgres=> SET ROLE july PASSWORD 'Gauss@123';
postgres=> SELECT * FROM emp;
 id | name |  phone_no   | card_no |     card_string     |        email         |   salary   |      birthday       
----+------+-------------+---------+---------------------+----------------------+------------+---------------------
  1 | anny | 13420002340 |       0 | ####-####-####-1234 | smithWu@163.com      | 99999.9990 | 1999-10-02 00:00:00
  2 | bob  | 18299023211 |       0 | ####-####-####-3456 | 66allen_mm@qq.com    |  9999.9990 | 1989-12-12 00:00:00
  3 | cici | 15512231233 |         |                     | jonesishere@sina.com |            | 1992-11-06 00:00:00
(3 rows)
  • (3)员工信息 phone_no、email 和 birthday 也是隐衷数据,更新脱敏策略 mask_emp,新增三个脱敏列。
postgres=> ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN phone_no WITH mask_partial(phone_no, '*', 4);
postgres=> ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN email WITH mask_partial(email, '*', 1, position('@' in email));
postgres=> ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN birthday WITH mask_full(birthday);

切换到用户 july,查看员工表 emp。

postgres=> SET ROLE july PASSWORD 'Gauss@123';
postgres=> SELECT * FROM emp;
 id | name |  phone_no   | card_no |     card_string     |        email         |   salary   |      birthday       
----+------+-------------+---------+---------------------+----------------------+------------+---------------------
  1 | anny | 134******** |       0 | ####-####-####-1234 | ********163.com      | 99999.9990 | 1970-01-01 00:00:00
  2 | bob  | 182******** |       0 | ####-####-####-3456 | ***********qq.com    |  9999.9990 | 1970-01-01 00:00:00
  3 | cici | 155******** |         |                     | ************sina.com |            | 1970-01-01 00:00:00
(3 rows)
  • (4)思考用户交互的敌对性,GaussDB (DWS) 提供零碎视图 redaction_policies 和 redaction_columns,不便用户间接查看更多脱敏信息。
postgres=> SELECT * FROM redaction_policies;
 object_schema | object_owner | object_name | policy_name |            expression             | enable | policy_description 
---------------+--------------+-------------+-------------+-----------------------------------+--------+--------------------
 public        | alice        | emp         | mask_emp    | ("current_user"() = 'july'::name) | t      | 
(1 row)
postgres=> SELECT object_name, column_name, function_info FROM redaction_columns;
 object_name | column_name |                                             function_info                                             
-------------+-------------+-------------------------------------------------------------------------------------------------------
 emp         | card_no     | mask_full(card_no)
 emp         | card_string | mask_partial(card_string, 'VVVVFVVVVFVVVVFVVVV'::text, 'VVVV-VVVV-VVVV-VVVV'::text, '#'::text, 1, 12)
 emp         | email       | mask_partial(email, '*'::text, 1, "position"(email, '@'::text))
 emp         | salary      | mask_partial(salary, '9'::text, 1, (length((salary)::text) - 2))
 emp         | birthday    | mask_full(birthday)
 emp         | phone_no    | mask_partial(phone_no, '*'::text, 4)
(6 rows)
  • (5)忽然某一天,公司外部可共享员工信息时,间接删除表 emp 的脱敏策略 mask_emp 即可。
postgres=> DROP REDACTION POLICY mask_emp ON emp;

更多用法详情,请参考 GaussDB (DWS) 8.1.1 产品文档。

数据脱敏实现背地的机密

GaussDB (DWS)数据脱敏性能,基于 SQL 引擎既有的实现框架,在受限用户执行查问语句过程中,实现内部不感知的实时脱敏解决。对于其外部实现,如上图所示。咱们将脱敏策略(Redaction Policy)视为表对象上绑定的规定,在优化器查问重写阶段,遍历 Query Tree 中 TargetList 的每个 TargetEntry,如若波及基表的某个脱敏列,且以后脱敏规定失效(即满足脱敏策略的失效条件且 enable 开启状态),则判定此 TargetEntry 中波及要脱敏的 Var 对象,此时,遍历脱敏列零碎表 pg_redaction_column,查找到对应脱敏列绑定的脱敏函数,将其替换成对应的 FuncExpr 即可。通过上述对 Query Tree 的重写解决,优化器会主动生成新的执行打算,执行器遵循新的打算执行,查问后果将对敏感数据做脱敏解决。

带有数据脱敏的语句执行,相较于原始语句,减少了数据脱敏的逻辑解决,势必会给查问带来额定的开销。这部分开销,次要受表的数据规模、查问指标列波及的脱敏列数、脱敏列采纳的脱敏函数三方面因素影响。

针对简略查问语句,以 tpch 表 customer 为例,针对上述因素开展测试,如下图所示。

图 (a)、(b) 中基表 customer 依据字段类型和特色,既有采纳 MASK_FULL 脱敏函数的,也有采纳 MASK_PARTIAL 脱敏函数的。MASK_FULL 对于任何长度和类型的原始数据,均只脱敏成固定值,所以,输入后果相较于原始数据,差别很大。图 (a) 显示不同数据规模下,脱敏和非脱敏场景简略查问语句的执行耗时。实心图标为非脱敏场景,空心图标为被限度用户,即脱敏场景。

可见,数据规模越大,带有脱敏的查问耗时与原始语句差别越大。图 (b) 显示 10x 数据规模下查问波及脱敏列数不同对于语句执行性能的影响。波及 1 列脱敏列时,带有脱敏的查问比原始语句慢,追溯发现,此列采纳的是 MASK_PARTIAL 局部脱敏函数,查问后果只是扭转了后果的格局,后果内容的长度并未变动,合乎“带有脱敏的语句执行会有相应的性能劣化”的实践猜测。随着查问波及脱敏列数的减少,咱们发现一个奇怪的景象,脱敏场景反倒比原始语句执行更快。进一步追溯多列场景下脱敏列关联的脱敏函数,发现,正是因为存在应用 MASK_FULL 全脱敏函数的脱敏列,导致输入后果集局部相比原始数据节俭很多工夫开销,从而多列查问下带有数据脱敏的简略查问反倒提速不少。

为了佐证上述猜想,咱们调整脱敏函数,所有脱敏列均采纳 MASK_PARTIAL 对原始数据做局部脱敏,从而可能在脱敏后果上保留原始数据的内部可读性。于是,如图 (c) 所示,当脱敏列均关联局部脱敏函数时,带有数据脱敏的语句比原始语句劣化 10% 左右,实践上讲,这种劣化是在可承受范畴的。上述测试仅针对简略的查问语句,当语句简单到带有汇集函数或简单表达式运算时,可能这种性能劣化会更显著。

总结

GaussDB (DWS)产品数据脱敏性能,是数据库产品内化和夯实数据安全能力的重要技术冲破,次要涵盖以下三个方面:

  1. 一套简略、易用的数据脱敏策略语法;
  2. 一系列可笼罩常见隐衷数据脱敏成果的、灵便配置的内置脱敏函数;
  3. 一个齐备、便捷的脱敏策略利用计划,使得原始语句在执行过程中能够实时、通明、高效地实现脱敏。

总而言之,此数据脱敏性能能够充沛满足客户业务场景的数据脱敏诉求,反对常见隐衷数据的脱敏成果,实现敏感数据的牢靠爱护。

点击关注,第一工夫理解华为云陈腐技术~

退出移动版