PostgreSQL数据脱敏插件介绍

来源:这里教程网 时间:2026-03-14 21:17:40 作者:

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乐知乐享交流群。欢迎关注文章的小伙伴随缘加入,进群请加本人微信skypkmoon并备注PG乐知乐享。

  • 相关推荐