By digoal
PostgreSQL security label is a security framework that opens the security label provider interface. By implementing this interface, you can achieve fine-grained data security control. As a result, some users can only see obfuscated data, for example.
For example, SELinux Label Lib: https://www.postgresql.org/docs/12/sepgsql.html
shared_preload_libraries = 'sepgsql'
SECURITY LABEL FOR selinux ON TABLE mytable IS 'system_u:object_r:sepgsql_table_t:s0';
For example, prohibit direct access to credit fields.
postgres=# CREATE TABLE customer (
cid int primary key,
cname text,
credit text
);
CREATE TABLE
postgres=# SECURITY LABEL ON COLUMN customer.credit
IS 'system_u:object_r:sepgsql_secret_table_t:s0';
SECURITY LABEL
Allow access to credit through function.
postgres=# CREATE FUNCTION show_credit(int) RETURNS text
AS 'SELECT regexp_replace(credit, ''-[0-9]+$'', ''-xxxx'', ''g'')
FROM customer WHERE cid = $1'
LANGUAGE sql;
CREATE FUNCTION
postgres=# SECURITY LABEL ON FUNCTION show_credit(int)
IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
SECURITY LABEL
An administrative user should perform the above operations.
postgres=# SELECT * FROM customer;
ERROR: SELinux: security policy violation
postgres=# SELECT cid, cname, show_credit(cid) FROM customer;
cid | cname | show_credit
-----+--------+---------------------
1 | taro | 1111-2222-3333-xxxx
2 | hanako | 5555-6666-7777-xxxx
(2 rows)
In this case, a regular user cannot reference customer credit. Still, a trusted procedure show_credit allows the user to print the customers’ credit card numbers with some digits masked out.
Query specific labels.
postgres=# select * from pg_seclabel;
objoid | classoid | objsubid | provider | label
--------+----------+----------+----------+-------
(0 rows)
postgres=# select * from pg_seclabels;
objoid | classoid | objsubid | objtype | objnamespace | objname | provider | label
--------+----------+----------+---------+--------------+---------+----------+-------
(0 rows)
In addition to SELinux, some plug-ins, such as anon, also use security label interfaces to mask sensitive information.
The first step is to label the user, indicating that the user needs to load the security label provider —> anon when querying data.
Then, label the object. Users who have performed labeling for objects will use the sensitive information masking function to mask sensitive information.
Example:
=# SELECT * FROM people;
id | fistname | lastname | phone
----+----------+----------+------------
T1 | Sarah | Conor | 0609110911
Step 1: Activate the dynamic masking engine.
=# CREATE EXTENSION IF NOT EXISTS anon CASCADE;
=# SELECT anon.start_dynamic_masking();
Step 2: Declare a masked user.
=# CREATE ROLE skynet LOGIN;
=# SECURITY LABEL FOR anon ON ROLE skynet IS 'MASKED';
Step 3: Declare the masking rules.
anon.Fake_last_name and anon.partial are two masking functions.
You should label security label on people.lastname and use anon.fake_last_name to filter functions safely. In other words, when you send a query, the fake_last_name function cleans the values of the field before entering the next step.
=# SECURITY LABEL FOR anonON COLUMN people.lastname
-# IS 'MASKED WITH FUNCTION anon.fake_last_name()';
=# SECURITY LABEL FOR anon ON COLUMN people.phone
-# IS 'MASKED WITH FUNCTION anon.partial(phone,2,$$******$$,2)';
Step 4: Connect with the masked user
=# \! psql peopledb -U skynet -c 'SELECT * FROM people;'
id | fistname | lastname | phone
----+----------+-----------+------------
T1 | Sarah | Stranahan | 06******11
The object is implemented in a masking function; when you query the object content, the masking function is carried out first and then returned.
Optimization algorithm:
Examples:
Add noise:
Random value obfuscation:
Display partial content:
Fake data should be randomly replaced by the contents of the fake library after loading the fake library.
Once the fake data is loaded, you have access to 12 faking functions:
For TEXT and VARCHAR columns, you can use the classic Lorem Ipsum generator:
You can write your own Masks and use your own functions as a mask. The function must either be destructive (like [Partial Scrambling]) or insert some randomness in the dataset (like [faking]).
For instance, if you wrote a function foo(), you can apply it as the following:
COMMENT ON COLUMN player.score IS 'MASKED WITH FUNCTION foo()';
If the type returned by the obfuscated function is not the same as the original type in the field, it can be converted and then returned.
For example, the faking functions will return values in TEXT data types. The random functions will return TEXT, INTEGER, or TIMESTAMP WITH TIMEZONE.
If the column you want to mask is in another data type (for instance, VARCHAR(30), then you need to add an explicit cast directly in the COMMENT declaration, as the following:
=# COMMENT ON COLUMN clients.family_name
-# IS 'MASKED WITH FUNCTION anon.fake_last_name()::VARCHAR(30)';
How to Switch a Secondary Physical Database to a Secondary Logical Database on PostgreSQL
PostgreSQL Deferrable Constraints: Unique, Primary Key, Foreign Key, and Exclude
Your Friend in a need - July 16, 2020
OpenAnolis - January 24, 2024
Alibaba Clouder - December 29, 2018
Alibaba Cloud Community - January 10, 2024
OpenAnolis - November 20, 2023
digoal - June 1, 2021
Alibaba Cloud PolarDB for PostgreSQL is an in-house relational database service 100% compatible with PostgreSQL and highly compatible with the Oracle syntax.
Learn MoreSDDP automatically discovers sensitive data in a large amount of user-authorized data, and detects, records, and analyzes sensitive data consumption activities.
Learn MoreAn online MPP warehousing service based on the Greenplum Database open source program
Learn MoreAn on-demand database hosting service for PostgreSQL with automated monitoring, backup and disaster recovery capabilities
Learn MoreMore Posts by digoal