更新时间:2023-04-19 GMT+08:00

数据脱敏

GaussDB(DWS)提供列级别的数据脱敏(Dynamic Data Masking)功能。针对某些敏感信息(如身份证号、手机号、银行卡号等),通过应用脱敏函数进行原始数据的变形改写,实现敏感隐私数据的可靠保护,从而增强产品在数据安全和隐私保护方面的能力。

  • 用户可以在指定表对象创建脱敏策略,并限定策略生效范围,且支持按角色匹配脱敏规则。详细内容请参见《SQL语法参考》中“CREATE REDACTION POLICY”章节。
  • 提供脱敏策略的修改语法,包括修改脱敏策略生效表达式、重命名脱敏策略,以及新增、修改、删除脱敏列信息。详细内容请参见《SQL语法参考》中“ALTER REDACTION POLICY”章节。
  • 删除脱敏策略,可以一键式删除脱敏策略在表的所有列字段上的脱敏函数信息。详细内容请参见《SQL语法参考》中“DROP REDACTION POLICY”章节。
  • GaussDB(DWS)提供MASK_NONE、MASK_FULL、MASK_PARTIAL三种内置脱敏函数,也支持使用C语言、PL/PGSQL语言创建的用户自定义脱敏函数。详细规格请参见《SQL语法参考》中“数据脱敏函数”章节。
  • 脱敏策略信息存储在系统表PG_REDACTION_POLICY,脱敏列信息存储在系统表PG_REDACTION_COLUMN
  • 用户可以通过系统视图REDACTION_POLICIESREDACTION_COLUMNS,更加方便地查看脱敏策略及脱敏列信息。
  • 通常,用户可以执行SELECT语句查看敏感信息的脱敏效果。如果语句有如下特征,则可能存在故意套取敏感数据的可能性,造成语句执行报错。
    • GROUP BY子句引用与目标列一样含有脱敏列的Target Entry作为分组。
    • DISTINCT作用在输出的脱敏列上。
    • 带有CTE的语句。
    • 涉及集合操作。
    • 子查询的目标列不是基表的脱敏列,而是基表脱敏列的表达式或者函数调用。
  • 支持脱敏数据的COPY TO或者GDS导出功能。由于脱敏数据的不可逆性,针对脱敏数据的二次运算无任何实际意义。
  • 禁止UPDATE、MERGE INTO、DELETE语句的目标列涉及脱敏列。
  • UPSERT语句允许通过EXCLUDED更新插入数据。如果引用脱敏列更新基表数据,存在误改数据的可能,执行会报错。
  • 8.2.0集群版本开始新增数据脱敏可算功能,通过guc参数enable_redactcol_computable控制。开启该功能后运算时使用原始数据,仅在导出数据库时对敏感数据进行脱敏处理。
  • 数据脱敏可算功能支持DML语句的目标列涉及脱敏列。
    • 目标表如果是普通表则将源表脱敏策略同步到目标表,实际数据为未经过脱敏处理的原始数据,查询时会根据脱敏策略进脱敏。
    • 目标表如果是外表,存在直接查看外表文件中数据的风险,所以实际数据为已经过脱敏处理的原始数据。

示例

以员工表emp,管理员用户alice以及普通用户matu、july为例,简要介绍数据脱敏过程。其中,用户alice是表emp的属主,表emp包含员工的姓名、手机号、邮箱、银行卡号、薪资等隐私数据。

  1. 创建用户alice、matu和july。
    1
    2
    3
    CREATE ROLE alice PASSWORD 'password';
    CREATE ROLE matu PASSWORD 'password';
    CREATE ROLE july PASSWORD 'password';
    
  2. 用户alice创建表emp并插入三条员工信息。
    1
    2
    3
    4
    CREATE TABLE emp(id int, name varchar(20), phone_no varchar(11), card_no number, card_string varchar(19), email text, salary numeric(100, 4), birthday date);
    INSERT INTO emp VALUES(1, 'anny', '13420002340', 1234123412341234, '1234-1234-1234-1234', 'smithWu@163.com', 10000.00, '1999-10-02');
    INSERT INTO emp VALUES(2, 'bob', '18299023211', 3456345634563456, '3456-3456-3456-3456', '66allen_mm@qq.com', 9999.99, '1989-12-12');
    INSERT INTO emp VALUES(3, 'cici', '15512231233', NULL, NULL, 'jonesishere@sina.com', NULL, '1992-11-06');
    
  3. 用户alice将表emp的读取权限授予用户matu、july。
    1
    GRANT SELECT ON emp TO matu, july;
    
  4. 仅用户alice可查看所有员工信息,matu和july对员工所有银行卡号和薪资数据不可见,于是,对表emp创建脱敏策略,分布为字段card_no、card_string和salary绑定脱敏函数。
    1
    2
    3
    4
    CREATE REDACTION POLICY mask_emp ON emp WHEN (current_user IN ('matu', 'july'))
     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);
    
  5. 切换到用户matu和july,查看员工表emp。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    SET ROLE matu PASSWORD 'password';
    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)
    SET ROLE july PASSWORD 'password';
    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)
    
  6. 用户matu也享有了员工所有信息的查看权限,只有july不可见,修改策略生效范围。
    1
    ALTER REDACTION POLICY mask_emp ON emp WHEN(current_user = 'july');
    
  7. 切换到用户matu和july,重新查看员工表emp。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    SET ROLE matu PASSWORD 'password';
    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)
    SET ROLE july PASSWORD 'password';
    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)
    
  8. 员工信息phone_no、email和birthday也是隐私数据,更新脱敏策略mask_emp,新增三个脱敏列。
    1
    2
    3
    ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN phone_no WITH mask_partial(phone_no, '*', 4);
    ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN email WITH mask_partial(email, '*', 1, position('@' in email));
    ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN birthday WITH mask_full(birthday);
    
  9. 切换到用户july,查看表emp数据。
    1
    2
    3
    4
    5
    6
    7
    8
    SET ROLE july PASSWORD 'password';
    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)
    
  10. 查询视图redaction_policies和redaction_columns,查看当前脱敏策略mask_emp的详细信息。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    SELECT * FROM redaction_policies;
     object_schema | object_owner | object_name | policy_name |            expression             | enable | policy_description | inherited 
    ---------------+--------------+-------------+-------------+-----------------------------------+--------+--------------------+-----------
     public        | alice        | emp         | mask_emp    | ("current_user"() = 'july'::name) | t      |                    | f       
    (1 row)
    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)
    
  11. 新增一列salary_info,若需要将文本类型的薪资信息统一脱敏成“*.*”,可以创建自定义脱敏函数实现。此处采用PL/PGSQL语言定义脱敏函数mask_regexp_salary,创建脱敏列时,只需自定义脱敏的函数名和参数列表,详细内容可参考用户自定义函数
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    ALTER TABLE emp ADD COLUMN salary_info TEXT;
    UPDATE emp SET salary_info = salary::text;
    CREATE FUNCTION mask_regexp_salary(salary_info text) RETURNS text AS
    $$
     SELECT regexp_replace($1, '[0-9]+','*','g');
    $$
    LANGUAGE SQL
    STRICT SHIPPABLE;
    ALTER REDACTION POLICY mask_emp ON emp ADD COLUMN salary_info WITH mask_regexp_salary(salary_info);
    SET ROLE july PASSWORD 'password';
    SELECT id, name, salary_info FROM emp;
     id | name | salary_info 
    ----+------+-------------
      1 | anny | *.*
      2 | bob  | *.*
      3 | cici | 
    (3 rows)
    
  12. 使用数据脱敏可算功能,确保GUC参数enable_redactcol_computable已提前开启。
    1
    2
    3
    4
    5
    6
    7
    8
    SET ROLE july PASSWORD 'password';
    SELECT id, name, salary_info FROM emp GROUP BY id, name, salary_info;
     id | name | salary_info 
    ----+------+-------------
      1 | anny | *.*
      2 | bob  | *.*
      3 | cici | 
    (3 rows)
    
  13. 无需为表emp设置敏感策略,删除脱敏策略mask_emp。
    1
    DROP REDACTION POLICY mask_emp ON emp;