试着使用PostgreSQL Anonymizer对数据进行匿名化和屏蔽
本文是2019年PostgreSQL Advent Calendaer的第16天。昨天的文章是由@masayuki038@github分享的“观察PostgreSQL JIT生成的代码”。本文介绍了在PostgreSQL中进行数据匿名化和脱敏处理的扩展工具PostgreSQL Anonymizer。
匿名化和屏蔽的含义是什么?
数据库中包含个人信息和企业机密等需要谨慎处理的数据。如果直接在开发、测试或分析过程中使用此类数据,则存在信息泄漏的风险。在这种情况下,一种安全处理数据的方法是匿名化。
匿名化是指從數據中去除可以識別個人的信息。掩蓋是匿名化的一種方式,即隱藏信息以實現匿名化。然而,匿名化和掩蓋在大多數情況下被用來表示幾乎相同的意思。
PostgreSQL Anonymizer 是什么?
PostgreSQL Anonymizer是一个在PostgreSQL中进行数据匿名化和掩码的扩展。 它由法国的Dalibo公司开发。之前也因为有Ora2Pg的开发者而有名。它的许可证与PostgreSQL相同,都是PostgreSQL许可证。
在PostgreSQL Anonymizer中,通过扩展PostgreSQL的数据定义语言(DDL),定义了数据掩码的规则。通过这样做,可以对数据进行掩码并进行更新,以SQL格式进行转储,并允许用户访问掩码的数据。
PostgreSQL Anonymizer 可与 PostgreSQL 9.6 及更高版本兼容。虽然在版本 9.5 中也可以使用,但是没有提供相关软件包,并且存在一些问题。此外,该项目仍处于开发中阶段,所以最好在了解这一点的基础上使用。
安装PostgreSQL Anonymizer。
如果您使用的是 CentOS 或其他基于 Red Hat 的操作系统,并且已经注册了 Yum 仓库,那么您可以轻松地安装 PostgreSQL Anonymizer,因为它包含在 PostgreSQL 开发者的 Yum 仓库中。关于安装 PostgreSQL 的详细步骤,请参考这篇文章。
在这里,我们假设已经安装了 CentOS 8 并且 PostgreSQL 12 。
首先,安装PostgreSQL Anonymizer 包的 postgresql_anonymizer12 版本。这里的数字12表示 PostgreSQL 的版本。请根据您使用的 PostgreSQL 版本进行相应更改。
# yum -y install postgresql_anonymizer12
(省略)
Installed:
postgresql_anonymizer12-0.5.0-1.rhel8.x86_64
perl-Carp-1.42-396.el8.noarch
perl-Exporter-5.72-396.el8.noarch
perl-libs-4:5.26.3-416.el8.x86_64
ddlx_12-0.15-1.rhel8.noarch
postgresql12-contrib-12.1-2PGDG.rhel8.x86_64
Complete!
安装postgresql_anonymizer12软件包会安装依赖的perl相关、ddlx、postgresql12-contrib软件包。ddlx软件包是从数据库对象中提取DDL的扩展。postgresql12-contrib软件包是PostgreSQL的附加模块,其中需要的是包含的tsm_system_rows扩展。tsm_system_rows扩展是指定从表中进行抽样的最大行数的扩展。perl相关软件包需要一部分附加模块。
然后,编辑PostgreSQL的配置文件postgresql.conf,在启动PostgreSQL服务器时将加载的共享库指定为参数shared_preload_libraries,并用逗号分隔添加表示PostgreSQL Anonymizer的anon。
# - Shared Library Preloading -
shared_preload_libraries = 'anon' # (change requires restart)
#local_preload_libraries = ''
#session_preload_libraries = ''
#jit_provider = 'llvmjit' # JIT library to use
为了使参数设置生效,将重新启动PostgreSQL服务。
# systemctl restart postgresql-12.service
最后,为了测试 PostgreSQL Anonymizer,创建并连接数据库 anondb,并安装 PostgreSQL Anonymizer 的扩展 anon,使用anon.load函数加载伪造数据用于数据掩码。
# su - postgres
Last login: Tue Dec 3 21:10:31 UTC 2019 on pts/0
$ createdb anondb
$ psql anondb
=# CREATE EXTENSION anon CASCADE;
NOTICE: installing required extension "tsm_system_rows"
NOTICE: installing required extension "ddlx"
CREATE EXTENSION
=# SELECT anon.load();
SELECT
load
------
t
(1 行)
=# \q
在执行CREATE EXTENSION命令时指定CASCADE的目的是为了同时安装有依赖关系的扩展。
现在,PostgreSQL Anonymizer 已经安装完成。
遮蔽规则的定义
生成测试数据并定义掩码规则。
首先,我们生成测试数据。创建用于存储部门和员工信息的表departments、employees,并准备一个用于注册数据的SQL文件init.sql。
CREATE TABLE departments (
id serial PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE employees (
id serial PRIMARY KEY,
last_name text NOT NULL,
first_name text NOT NULL,
email text NOT NULL,
salary int NOT NULL,
department_id int NOT NULL REFERENCES departments (id),
birth date NOT NULL
);
INSERT INTO departments (name) VALUES
('営業部'),
('技術部');
INSERT INTO employees (last_name, first_name, email, salary, department_id, birth) VALUES
('佐藤', '太郎', 'sato@example.com', 300000, 1, '1987-01-02'),
('鈴木', '次郎', 'suzuki@example.com', 300000, 2, '1988-03-04'),
('高橋', '三郎', 'takahashi@example.com', 350000, 1, '1989-05-06'),
('田中', '花子', 'tanaka@example.com', 350000, 2, '1990-07-08'),
('伊藤', '雪子', 'ito@example.com', 400000, 1, '1991-09-10'),
('渡辺', '月子', 'watanabe@example.com', 400000, 2, '1992-11-12');
接下来,将读取并执行 init.sql 文件。
$ psql -f init.sql anondb
CREATE TABLE
CREATE TABLE
INSERT 0 2
INSERT 0 6
$ psql anondb
=# SELECT * FROM departments;
id | name
----+--------
1 | 営業部
2 | 技術部
(2 行)
=# SELECT * FROM employees;
id | last_name | first_name | email | salary | department_id | birth
----+-----------+------------+-----------------------+--------+---------------+------------
1 | 佐藤 | 太郎 | sato@example.com | 300000 | 1 | 1987-01-02
2 | 鈴木 | 次郎 | suzuki@example.com | 300000 | 2 | 1988-03-04
3 | 高橋 | 三郎 | takahashi@example.com | 350000 | 1 | 1989-05-06
4 | 田中 | 花子 | tanaka@example.com | 350000 | 2 | 1990-07-08
5 | 伊藤 | 雪子 | ito@example.com | 400000 | 1 | 1991-09-10
6 | 渡辺 | 月子 | watanabe@example.com | 400000 | 2 | 1992-11-12
(6 行)
下一步,将定义一个遮蔽规则。规定列名为email的列中存储的员工Eメール地址将通过anon.partial_email函数进行遮蔽。
=# SECURITY LABEL FOR anon ON COLUMN employees.email
-# IS 'MASKED WITH FUNCTION anon.partial_email(email)';
SECURITY LABEL
使用 SECURITY LABEL 命令来定义掩码规则。 SECURITY LABEL 命令是用来定义安全标签的命令。我之前误以为它是 SELinux 专用命令,但通过指定标签提供程序,可以应用任意访问控制。在 FOR 后面,作为标签提供程序,可以指定 anon,ON COLUMN 后面,作为掩码目标列,可以指定 employees.email,IS 后面,作为标签,可以指定掩码规则。
マスキングルールはanon.partial_email函数的用法。anon.partial_email函数是由PostgreSQL Anonymizer提供的一种掩码函数,它保留电子邮件地址的本地部分、域名的前两个字符和最后一个子域名,并用******替换其余部分。例如,电子邮件地址sato@example.com会被掩码为sa******@ex******.com。
您可以使用系统视图`pg_seclabels`来确认已定义的掩码规则。此外,要删除掩码规则,您可以使用`SECURITY LABEL`命令并指定`NULL`标签来执行。
=# SELECT * FROM pg_seclabels;
objoid | classoid | objsubid | objtype | objnamespace | objname | provider | label
--------+----------+----------+---------+--------------+-----------------+----------+------------------------------------------------
16645 | 1259 | 4 | column | 2200 | employees.email | anon | MASKED WITH FUNCTION anon.partial_email(email)
(1 行)
就地匿名化
“原地匿名化(in-place anonymization)是一种将数据进行屏蔽并进行更新的功能。”
要进行原地匿名化,可以使用 anonymize_database、anonymize_table 和 anonymize_column 函数。根据函数名称就可以理解,anonymize_database 函数将对数据库中的所有表进行匿名化,anonymize_table 函数将匿名化指定的表,anonymize_column 函数将匿名化指定表的列。
=# BEGIN;
BEGIN
=# SELECT anon.anonymize_database();
anonymize_database
--------------------
t
(1 行)
=# SELECT * FROM employees;
id | last_name | first_name | email | salary | department_id | birth
----+-----------+------------+-----------------------+--------+---------------+------------
1 | 佐藤 | 太郎 | sa******@ex******.com | 300000 | 1 | 1987-01-02
2 | 鈴木 | 次郎 | su******@ex******.com | 300000 | 2 | 1988-03-04
3 | 高橋 | 三郎 | ta******@ex******.com | 350000 | 1 | 1989-05-06
4 | 田中 | 花子 | ta******@ex******.com | 350000 | 2 | 1990-07-08
5 | 伊藤 | 雪子 | it******@ex******.com | 400000 | 1 | 1991-09-10
6 | 渡辺 | 月子 | wa******@ex******.com | 400000 | 2 | 1992-11-12
(6 行)
=# ROLLBACK;
ROLLBACK
=# \q
另外,原地匿名化会更新数据本身,导致原始数据丢失。而且,由于需要更新表中的所有数据,执行过程可能需要很长时间。在后续的匿名备份中,对数据进行掩码处理并进行备份,然后进行还原可能会更快。
匿名转储
匿名转储是一种能够将数据掩盖并以SQL格式导出的功能。
要执行匿名转储,请执行anon.dump函数。如果要转储到文件中,请在命令行中执行函数,并将其输出重定向。在此过程中,为了抑制多余的消息、对齐和除行外的输出,需指定-qAt选项。
$ psql -qAt -c "SELECT anon.dump()" anondb
(省略)
COPY departments
FROM STDIN
CSV QUOTE AS '"'
DELIMITER ',';
1,営業部
2,技術部
\.
COPY employees
FROM STDIN
CSV QUOTE AS '"'
DELIMITER ',';
1,佐藤,太郎,sa******@ex******.com,300000,1,1987-01-02
2,鈴木,次郎,su******@ex******.com,300000,2,1988-03-04
3,高橋,三郎,ta******@ex******.com,350000,1,1989-05-06
4,田中,花子,ta******@ex******.com,350000,2,1990-07-08
5,伊藤,雪子,it******@ex******.com,400000,1,1991-09-10
6,渡辺,月子,wa******@ex******.com,400000,2,1992-11-12
\.
动态遮罩
动态遮蔽是一种动态地对数据进行遮蔽,并允许用户访问的功能。通过在另一个模式下定义一个具有相同名称的视图,并应用遮蔽函数,然后切换模式以允许用户访问,从而实现此功能。
首先,执行anon.start_dynamic_masking函数以启用动态屏蔽。
=# SELECT anon.start_dynamic_masking();
start_dynamic_masking
-----------------------
t
(1 行)
接下来,我们将创建一个名为masked_user的用户,让他可以访问被蒙面的数据。
=# CREATE ROLE masked_user LOGIN;
CREATE ROLE
=# SECURITY LABEL FOR anon ON ROLE masked_user IS 'MASKED';
SECURITY LABEL
=# GRANT SELECT ON ALL TABLES IN SCHEMA mask TO masked_user;
GRANT
=# \q
使用CREATE ROLE命令创建具有LOGIN权限的用户,并使用SECURITY LABEL命令赋予其MASKED标签。带有MASKED标签的用户访问将自动切换到包含被掩盖表的模式mask。访问权限需要手动设置。使用GRANT命令授予mask模式中所有表的SELECT权限。
最后,将作为masked_user用户连接到anondb数据库,并验证数据已被掩码处理。
$ psql -U masked_user anondb
=> SELECT * FROM employees;
id | last_name | first_name | email | salary | department_id | birth
----+-----------+------------+-----------------------+--------+---------------+------------
1 | 佐藤 | 太郎 | sa******@ex******.com | 300000 | 1 | 1987-01-02
2 | 鈴木 | 次郎 | su******@ex******.com | 300000 | 2 | 1988-03-04
3 | 高橋 | 三郎 | ta******@ex******.com | 350000 | 1 | 1989-05-06
4 | 田中 | 花子 | ta******@ex******.com | 350000 | 2 | 1990-07-08
5 | 伊藤 | 雪子 | it******@ex******.com | 400000 | 1 | 1991-09-10
6 | 渡辺 | 月子 | wa******@ex******.com | 400000 | 2 | 1992-11-12
(6 行)
=> \q
因此,由于动态掩码是通过切换架构来实现的,所以只能将掩码目标架构限制在一个。默认情况下是公共架构,可以在anon.start_dynamic_masking函数的第一个参数中进行指定。此外,还可以通过第二个参数来指定存储掩码表的架构。
PostgreSQL Anonymizer 的介绍到此为止。虽然本次没有介绍,但是还有其他的掩码函数可用,包括添加噪音、乱序、随机化、伪装、部分混淆、通用化和k-匿名化等。需要注意的是,仅准备了英语的伪装数据,但也可以使用CSV格式创建和加载日语的伪装数据。