暂无图片
暂无图片
4
暂无图片
暂无图片
暂无图片

PostgreSQL数据脱敏插件介绍

原创 多米爸比 2022-12-23
2316

openGauss 2.0版本已经内置动态脱敏的特性,相关特性介绍可以参考我写过的这篇文章:<<openGauss数据动态脱敏之不同策略测试>>

PostgreSQL内核目前还不支持里这个特性,但gitlab上有个插件Anonymizer支持该特性,本文参考官方文档进行简单的测试。

1.安装部署Anonymizer

https://postgresql-anonymizer.readthedocs.io/en/latest/INSTALL/#install-from-source

参考上面源码编译方式,本地编译示例如下:

$ make
cp anon.sql anon/anon--1.1.0.sql
cp data/*.csv anon/
cp python/populate.py anon/
$ make install
cp anon.sql anon/anon--1.1.0.sql
cp data/*.csv anon/
cp python/populate.py anon/
/usr/bin/mkdir -p '/opt/pg15/share/postgresql/extension'
/usr/bin/mkdir -p '/opt/pg15/share/postgresql/extension/anon'
/usr/bin/mkdir -p '/opt/pg15/lib/postgresql'
install -d /opt/pg15/bin
install -m 0755 bin/pg_dump_anon.sh /opt/pg15/bin
/usr/bin/install -c -m 644 .//anon.control '/opt/pg15/share/postgresql/extension/'
/usr/bin/install -c -m 644 .//anon/*  '/opt/pg15/share/postgresql/extension/anon/'
/usr/bin/install -c -m 755  anon.so '/opt/pg15/lib/postgresql/'

数据库级别配置动态库

create database foo;
alter database foo set session_preload_libraries = 'anon';

在示例数据库foo中创建anon扩展插件,anon依赖加密插件pgcrypto,需要先创建pgcrypto:

\c foo
create extension pgcrypto;
create extension anon;

创建完后检查扩展插件

foo=# \dx
                  List of installed extensions
   Name   | Version |   Schema   |         Description          
----------+---------+------------+------------------------------
 anon     | 1.1.0   | public     | Data anonymization tools
 pgcrypto | 1.3     | public     | cryptographic functions
 plpgsql  | 1.0     | pg_catalog | PL/pgSQL procedural language
(3 rows)

如果需要使用伪造函数,需要执行下面的初始化函数,生成伪造数据。

SELECT anon.init();

2.anon参数设置

anon插件主要支持如下参数的设置:

  • anon.algorithm:脱敏函数使用的hash算法,默认为sha256,支持md5、sha256、sha384和sha512等,需要超级用户权限才可设置。
  • anon.salt:脱敏函数可使用的salt值,一般建议每个数据库设置不一样的值,需要超级用户权限才可设置。
  • anon.maskschema:动态脱敏视图存储的模式名称,默认名称为mask。
  • anon.sourceshema:动态脱敏引擎对表数据生效的schema源,默认是public模式。
  • anon.restrict_to_trusted_schemas:可限制脱敏规则必须在指定的schema范围内来提升安全性,默认是off。

进行如下设置:

alter database foo set anon.restrict_to_trusted_schemas = on;
alter database foo set anon.salt = 'db_foo_Secret_Salt';

重新连接数据库后执行如下语句:

select anon.start_dynamic_masking();

3.配置脱敏规则

数据脱敏规则通过security labels进行声明:

CREATE TABLE public.player(id SERIAL, name TEXT, points INT);

INSERT INTO public.player VALUES
  ( 1, 'Kareem Abdul-Jabbar', 38387),
  ( 5, 'Michael Jordan', 32292 );

SECURITY LABEL FOR anon ON COLUMN player.name
  IS 'MASKED WITH FUNCTION anon.fake_last_name()';

SECURITY LABEL FOR anon ON COLUMN player.id
  IS 'MASKED WITH VALUE NULL';

如果安全标签声明内容里包含字符串标量,可以使用C风格的转义或使用双美元符号。
使用C风格转义:

SECURITY LABEL FOR anon ON COLUMN player.name
  IS E'MASKED WITH VALUE \'CONFIDENTIAL\'';

或使用双美元符:

SECURITY LABEL FOR anon ON COLUMN player.name
  IS 'MASKED WITH VALUE $$CONFIDENTIAL$$';

使用表达式

SECURITY LABEL FOR anon ON COLUMN player.name
  IS 'MASKED WITH VALUE CASE WHEN name IS NULL
                             THEN $$John$$
                             ELSE anon.random_string(LENGTH(name))
                             END';

移除单个列的脱敏规则

SECURITY LABEL FOR anon ON COLUMN player.name IS NULL;

移除所有表的脱敏规则

SELECT anon.remove_masks_for_all_columns();

注意:分区表需要在分区上独立进行设置。

4.脱敏函数

anon提供了8种脱敏策略,可以对不同的列分别使用不同的脱敏策略:

  • Destruction(重构)
  • Adding Noise(噪音化)
  • Randomization(随机化)
  • Faking(伪造)/Advanced Faking(高级伪造)
  • Pseudonymization(笔名化)
  • Generic Hashing(哈希)
  • Partial scrambling(部分遗漏)
  • Generalization((泛化))

Destruction(重构):替换为单个静态值

SECURITY LABEL FOR anon
  ON COLUMN users.address
  IS 'MASKED WITH VALUE ''CONFIDENTIAL'' ';

Adding Noise(噪音化):它是对日期和数值添加一个方差,有两种函数形式:

  • anon.noise(original_value,ratio) 其中original_value可以是integer、bigint或double precision。如果ratio为0.33,返回值将是原始值的33%上下波动。
  • anon.dnoise(original_value, interval)其中original_value可以是日期、时间戳或时间。如果间隔为2天,返回值将是原始值前后2天波动。

Randomization(随机化)
基本随机值

  • anon.random_date()返回日期
  • anon.random_string(n)返回包含n个字母的文本值
  • anon.random_zip()返回一个5位代码
  • anon.random_phone§返回一个以p为前缀的手机号
  • anon.random_hash(seed)返回给定种子的随机字符串

边界随机值

  • anon.random_date_between(d1,d2)返回d1和d2之间的日期
  • anon.random_int_between(i1,i2)返回i1和i2之间的整数
  • anon.random_bigint_between(b1,b2)返回b1和b1之间的大整数

基于数组的随机值

  • anon.random_in(ARRAY[1,2,3])返回1到3之间的整数
  • anon.random_in(ARRAY[‘red’,‘green’,‘blue’])返回文本

Faking(伪造)/Advanced Faking(高级伪造):伪造的想法是用随机但合理的值取代敏感数据。
为了使用伪造函数,需要先调用init函数

SELECT anon.init();

加载数据后,可以访问以下伪造函数:

  • anon.fake_address()返回完整的邮寄地址
  • anon.fake_city()返回城市名称
  • anon.fake_country()返回国家名称
  • anon.fake_company()返回公司名称
  • anon.fake_email()返回有效的电子邮件地址
  • anon.fake_first_name()返回名字
  • anon.fake_iban()返回有效的IBAN
  • anon.fake_last_name()返回姓氏
  • anon.fake_postcode()返回有效的邮政编码
  • anon.fake_siret()返回有效的SIRET

高级伪造请查看:PostgreSQL Faker

Pseudonymization(笔名化):类似于伪造,主要区别在于笔名化是确定性的,相同的seed和salt返回相同的值。

为了使用笔名化函数,需要先调用init函数

SELECT anon.init();

加载数据后,可以访问以下函数:

  • anon.pseudo_first_name(‘seed’,‘salt’)返回名字
  • anon.pseudo_last_name(‘seed’,‘salt’)返回姓氏
  • anon.pseudo_email(‘seed’,‘salt’)返回有效的电子邮件地址
  • anon.pseudo_city(‘seed’,‘salt’)返回城市名称
  • anon.pseudo_country(‘seed’,‘salt’)返回国家名称
  • anon.pseudo_company(‘seed’,‘salt’)返回公司名称
  • anon.pseudo_iban(‘seed’,‘salt’)返回有效的IBAN
  • anon.pseudo_siret(‘seed’,‘salt’)返回有效的SIRET

第二个参数salt是可选的,salt可以增加复杂性,避免字典和暴力攻击。seed可以是与主题相关的任何信息。例如,我们可以始终使用给定的登录名作为seed为给定的人生成相同的虚假电子邮件地址。

SECURITY LABEL FOR anon
  ON COLUMN users.emailaddress
  IS 'MASKED WITH FUNCTION anon.pseudo_email(users.login)';

Generic Hashing(哈希)

  • anon.set_secret_salt(value) 自定义salt值,初始化扩展时会生成随机salt值。
  • anon.set_algorithm(value) 自定义哈希算法,可选值为:md5、sha1、sha224、sha256、sha384或sha512,默认值哈希算法是sha256。
  • anon.hash(value) 使用salt和哈希算法计算hash值。
  • anon.digest(value,salt,algorithm) 允许从预定义的列表中选择salt和哈希算法。

Partial scrambling(部分遗漏)
例如掩盖信用卡中间号码或邮箱地址

  • anon.partial(‘4012 3452 4568 2396’,2,‘XXXX’,3)
  • anon.partial_email(‘daamien@gmail.com’)

Generalization(泛化):泛化是将原始值替换为包含该值的范围。例如,与其说“保罗42岁”,不如说“保罗在40到50岁之间”。

  • generalize_int4range(value, step)
  • generalize_int8range(value, step)
  • generalize_numrange(value, step)
  • generalize_daterange(value, step)
  • generalize_tsrange(value, step)
  • generalize_tstzrange(value, step)

其中value是将要泛化的数据,step是每个范围的步长。

除了上面的八种策略,我们还可以自定义脱敏函数,例如在模式bar内定义脱敏函数foo():

SECURITY LABEL FOR anon ON SCHEMA bar IS 'TRUSTED';

SECURITY LABEL FOR anon ON COLUMN player.score
IS 'MASKED WITH FUNCTION bar.foo()';

下面的示例,对JSON类型进行自定义脱敏处理。

SECURITY LABEL FOR anon ON SCHEMA custom_masks IS 'TRUSTED';

CREATE FUNCTION custom_masks.remove_last_name(j JSONB)
RETURNS JSONB
VOLATILE
LANGUAGE SQL
AS $func$
SELECT
  json_build_object(
    'employees' ,
    array_agg(
      jsonb_set(e ,'{lastName}', to_jsonb(anon.fake_last_name()))
    )
  )::JSONB
FROM jsonb_array_elements( j->'employees') e
$func$;

5.静态脱敏

静态脱敏会损坏原始数据,使用时需要额外小心。

定义完脱敏规则后使用下面的函数替换真实数据。

select anon.anonymize_database()

也可使用下面的函数进行局部处理:

SELECT anon.anonymize_table('customer');
SELECT anon.anonymize_column('customer','zipcode');

6.动态脱敏

我们可以将脱敏数据放到一个脱敏用户下,其他用户仍然可以访问原始数据。

示例:

CREATE TABLE people (id TEXT, firstname TEXT, lastname TEXT, phone TEXT);
INSERT INTO people VALUES ('T1','Sarah', 'Conor','0609110911');

步骤一:激活动态脱敏引擎

CREATE EXTENSION IF NOT EXISTS anon CASCADE;
SELECT anon.start_dynamic_masking();

步骤二:定义脱敏用户

CREATE ROLE skynet LOGIN;

SECURITY LABEL FOR anon ON ROLE skynet
IS 'MASKED';

步骤三:定义脱敏规则

SECURITY LABEL FOR anon ON COLUMN people.lastname
IS 'MASKED WITH FUNCTION anon.random_string(4)';

SECURITY LABEL FOR anon ON COLUMN people.phone
IS 'MASKED WITH FUNCTION anon.partial(phone,2,$$******$$,2)';

步骤四:使用脱敏用户查询

\c - skynet

foo=> select * from people;
 id | firstname | lastname |   phone    
----+-----------+----------+------------
 T1 | Sarah     | ROKS     | 06******11
(1 row)

更改脱敏列的数据类型:当动态脱敏引擎被激活时,如果列上有脱敏规则,则不允许更改列的数据类型。

修改脱敏列需要临时停止脱敏引擎:

BEGIN;
SELECT anon.stop_dynamic_masking();
ALTER TABLE people ALTER COLUMN phone TYPE VARCHAR(255);
SELECT anon.start_dynamic_masking();
COMMIT;

删除脱敏表:动态脱敏引擎将在脱敏表上构建脱敏视图,直接删除脱敏表会提示这样的错误:

ERROR:  cannot drop table people because other objects depend on it
DETAIL:  view mask.people depends on table people
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

需要使用CASCADE选项,级联删除脱敏视图。

DROP TABLE people CASCADE;

7.脱敏数据导出

如果需要使用脱敏用户导出数据,需要使用工具pg_dump_anon,工具安装参考:

https://postgresql-anonymizer.readthedocs.io/en/latest/anonymous_dumps/#with-go

8.抽样脱敏

如果是测试目的,仅提取和脱敏10%的数据,示例如下:

CREATE TABLE http_logs (
  id integer NOT NULL,
  date_opened DATE,
  ip_address INET,
  url TEXT
);

SECURITY LABEL FOR anon ON COLUMN http_logs.ip_address
IS 'MASKED WITH VALUE NULL';

SECURITY LABEL FOR anon ON TABLE http_logs
IS 'TABLESAMPLE BERNOULLI(10)';

也可以在数据库级别定义抽样:

SECURITY LABEL FOR anon ON DATABASE foo
IS 'TABLESAMPLE SYSTEM(33)';

9.术语定义

https://postgresql-anonymizer.readthedocs.io/en/latest/concepts/

  • Dynamic Masking
  • Permanent Destruction
  • Deletion/Nullification
  • Static Substitution
  • Variance
  • Generalization
  • Shuffling
  • Randomization
  • Partial scrambling
  • Custom rules
  • Pseudonymization

10.相关链接

官方链接

https://gitlab.com/dalibo/postgresql_anonymizer/

官方文档

https://postgresql-anonymizer.readthedocs.io/en/stable/

目前该功能还处于测试阶段,作者建议2.0版本才可用于生产,敬请关注。

保持联系

本人组建了一个粉丝群:PG乐知乐享交流群。欢迎关注文章的小伙伴随缘加入,进群请加微信并备注PG乐知乐享。

456.png

最后修改时间:2023-02-01 16:15:42
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论