数据隐私权策略

“数据隐私权”是指保护个人身份信息 (PII) 等数据,使那些不应该接触到此类数据的人员无法对其进行访问。本页面介绍了几种保护数据隐私的方法,可用于在 Cloud SQL 中保护个人身份信息。

您可以使用 Cloud SQL 安全地存储个人身份信息。您想要确保此类信息在处理过程中受到最高级别的隐私保护,以免无意间将其变成可访问。例如,如果将信用卡信息或医疗保健数据存储在数据库中,则可使用 Cloud SQL 隐藏或遮盖个人身份信息,防止无权限的用户对其进行访问。

使用以下策略可帮助您在 Cloud SQL 中保护个人身份信息:

列级安全性

借助列级安全性,您可以限制谁能查看数据库表特定列中的内容。列级权限适用于 INSERTUPDATESELECTREFERENCES 语句。

例如,假设在某个零售网站,您想要管理 Jack 和 Alice 这两个用户的个人身份信息。

--User: "admin"

CREATE SCHEMA secure_schema;

CREATE TABLE secure_schema.user_details(id bigint, name text, age smallint, email_id text, password text);

--For this example, passwords are stored in plain text for demonstration
--purposes only. In production, never store passwords in plain text.

INSERT INTO secure_schema.user_details VALUES(1,'jack',34,'jack@example.com','testpass');
INSERT INTO secure_schema.user_details VALUES(2,'alice',37,'alice@example.com','testpass');

GRANT USAGE ON SCHEMA secure_schema TO analyst_ro;

--Grant read permissions on specific columns only.

GRANT SELECT (id, name, age) ON secure_schema.user_details TO analyst_ro;

--User: "analyst_ro"

SELECT * FROM secure_schema.user_details;
ERROR:  permission denied for table user_details

SELECT name, age, password FROM secure_schema.user_details;
ERROR:  permission denied for table user_details

SELECT id, name,age FROM secure_schema.user_details;
 id | name  | age
----+-------+----
  1 | jack  |  34
  2 | alice |  37

如果您在 SELECT 语句中包含受限制的列或输入 SELECT *,则系统会显示错误消息。Cloud SQL 会保护这些列中的 Jack 和 Alice 的个人身份信息。

您还可以使用单个 GRANT 语句来组合不同的权限。

GRANT SELECT (id,name,age), UPDATE (name) ON secure_schema.user_details TO analyst_ro;

基于视图的方法

您还可以依据某个表来创建视图,排除或遮盖要向其他用户隐藏的列,以及提供对视图(而非表)的访问权限,从而实现列级安全性。

以下示例展示了如何为零售网站使用基于视图的方法来保护 Jack 和 Alice 的个人身份信息:

--User: "admin"

CREATE SCHEMA analyst_ro;
CREATE VIEW analyst_ro.user_details AS SELECT id, name, age FROM secure_schema.user_details;
GRANT USAGE ON SCHEMA analyst_ro TO analyst_ro;
GRANT SELECT ON analyst_ro.user_details TO analyst_ro;

--User: "analyst_ro"

SELECT id,name,age FROM user_details;
 id | name  | age
----+-------+----
  1 | jack  |  34
  2 | alice |  37

SELECT * FROM user_details;
 id | name  | age
----+-------+----
  1 | jack  |  34
  2 | alice |  37

在此示例中,系统为视图创建了单独的架构以使其与对应表同名。通过基于视图的方法,您可以使用 SELECT *

此外,您还可以创建视图并遮盖数据库表列,以免无权限的用户看到已遮盖的个人身份信息。

CREATE VIEW analyst_ro.user_details AS SELECT id, name, age, 'redacted@example.com' as email_id,'*****'::text as password FROM secure_schema.user_details;

SELECT * FROM user_details;
 id | name  | age |     email_id         | password
----+-------+-----+----------------------+---------
  1 | jack  |  34 | redacted@example.com | *****
  2 | alice |  37 | redacted@example.com | *****

行级安全性

借助列级安全性和基于视图的方法,您可以向特定用户隐藏数据库表列中的个人身份信息。但是,有时您希望过滤此数据,并授予对特定表行的访问权限。此表包含只有符合特定条件的用户才能访问的个人身份信息。这称为“行级安全性”

对于用户仅对自己的个人身份信息拥有读写访问权限的多租户应用,行级安全性很有用。在 Cloud SQL 中,表可以具有行级安全策略,这些策略以每个用户为单位,限制用户可通过创建查询来查看哪些行,或限制用户可通过运行数据修改命令来插入、更新或删除哪些行。

对于零售网站示例,您可以为 Jack 和 Alice 实施行级安全性,以便他们能够查看自己的个人身份信息,但无法对其进行修改或删除。

--User: "admin"
--Create and enable a policy for row-level security

CREATE POLICY user_details_rls_pol ON secure_schema.user_details FOR ALL TO PUBLIC USING (name=current_user);
ALTER TABLE secure_schema.user_details ENABLE ROW LEVEL SECURITY;

SELECT * FROM secure_schema.user_details;
 id | name  | age |     email_id      | password
----+-------+-----+-------------------+---------
  1 | jack  |  34 | jack@example.com  | testpass
  2 | alice |  37 | alice@example.com | testpass

--User: "jack"

SELECT * FROM secure_schema.user_details;
 id | name | age |    email_id      | password
----+------+-----+------------------+---------
  1 | jack |  34 | jack@example.com | testpass

--User: "alice"

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id       | password
----+-------+-----+-------------------+---------
  2 | alice |  37 | alice@example.com | testpass

如果用户分配有具有 BYPASSRLS 属性的角色,则在访问表时可以绕过行级安全性。表所有者也可以绕过行级安全性。如果您要使表所有者受行级安全保护约束,请使用 ALTER TABLE ... FORCE ROW LEVEL SECURITY 命令。

有时,您不想对数据库表行应用行级安全性。例如,如果使用 pg_dump 对表进行备份,则表示您不希望备份省略任何行。为防止出现这种情况,对于执行备份的用户,请将 row_security 配置参数设置为 OFF。如果您根据行级安全性对任何行进行过滤,则系统会显示错误消息。

遮盖和匿名化数据

除了使用基于视图的方法遮盖数据之外,您还可以使用 postgresql_anonymizer 扩展程序来遮盖数据。此扩展程序会遮盖或替换 PostgreSQL 数据库中的个人身份信息或商业敏感数据。

与基于视图的方法相比,使用扩展程序可提供以下优势:

  • 您可使用各种遮盖函数,例如替换、随机化、伪造、假名化、部分加扰、重排、加噪和泛化。

  • 您可以生成有意义的遮盖数据,以用于功能测试和数据处理。

  • 您可以使用 PostgreSQL 数据定义语言 (DDL) 来声明遮盖规则,并在表定义中指定匿名化策略。

安装并配置 postgresql_anonymizer 扩展程序

如需在 Cloud SQL 实例上使用此扩展程序,请完成以下步骤:

  1. 修改实例,然后将 cloudsql.enable_anon flag 设置为 on。如需了解如何设置标志并查看此扩展程序支持的标志,请参阅配置数据库标志

  2. 通过运行以下命令在数据库中创建扩展程序:

    --Connect to the PostgreSQL database
    
    CREATE EXTENSION IF NOT EXISTS anon CASCADE;
    SELECT anon.init();
    

安装并配置扩展程序后,在实例上使用它来实现动态遮盖静态遮盖匿名转储等匿名化策略。

动态遮盖

使用动态遮盖为特定用户定义遮盖规则。这些用户无法看到个人身份信息,但可看到经过遮盖的数据,其他所有用户会看到未被遮盖的数据。在生产环境中,如果您不想修改个人身份信息,而只希望向特定用户隐藏个人身份信息,则这是很有用的。

对于零售网站示例,您可以实现动态遮盖,以便管理员可以查看 Jack 和 Alice 的未遮盖的电子邮件地址与密码,而分析师只能查看经过遮盖的数据。

--Activate the dynamic masking engine

SELECT anon.start_dynamic_masking();

--Declare the masking user and masking rules
--analyst_ro is the masked user with select privileges on the
--user_details table

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

SECURITY LABEL FOR anon ON COLUMN secure_schema.user_details.email_id IS 'MASKED WITH FUNCTION anon.fake_email()';
SECURITY LABEL FOR anon ON COLUMN secure_schema.user_details.password  IS 'MASKED WITH FUNCTION anon.hash(password)';

--User: "admin" (can see all unmasked data)

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id       | password
----+-------+-----+------------  -----+---------
  1 | jack  |  34 | jack@example.com  | testpass
  2 | alice |  37 | alice@example.com | testpass

--User:"analyst_ro" (note that the "email_id" and "password" columns are
--replaced with masked data,)
--Data in the password column is truncated for better formatting.

SELECT * FROM secure_schema.user_details;
 id | name  | age |       email_id         | password
----+-------+-----+-----------------  -----+----------------
  1 | jack  |  34 | alisontodd@example.com | 13d249f2cb4127b
  2 | alice |  37 | amanda35@example.com   | 13d249f2cb4127b

静态遮盖

根据遮盖规则中定义的条件,使用静态遮盖移除表中的个人身份信息,并将此信息替换为经过遮盖的数据。用户无法检索未经遮盖的数据。在测试环境中,如果您想修改个人身份信息,但不希望任何用户查看此信息,则这种方法很有用。

对于零售网站示例,您可以实施静态遮盖,以便任何用户都无法查看 Jack 和 Alice 的未遮盖的电子邮件地址与密码。他们只能查看经遮盖的数据。

--User: "admin"

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id       | password
----+-------+-----+--------------  ---+---------
  1 | jack  |  34 | jack@example.com  | testpass
  2 | alice |  37 | alice@example.com | testpass

--Apply earlier defined masking rules to the table permanently.
--Now all users see masked data only.

SELECT anon.anonymize_table('secure_schema.user_details');
 anonymize_table
-----------------
 t

--User: "analyst_ro"
--Data in the password column is truncated for better formatting.

select * from secure_schema.user_details;
 id | name  | age |           email_id              |  password
----+-------+-----+-------------------------  ------+---------------
  1 | jack  |  34 | christophercampbell@example.com | 13d249f2cb412c
  2 | alice |  37 | annebenitez@example.com         | 13d249f2cb4127

匿名转储

使用匿名转储将经遮盖的数据导出到 SQL 文件。对于零售网站示例,您可以为 user_details 表中包含的遮盖的数据创建转储文件。

--Launch pg_dump_anon with the masked user to apply earlier defined --masking rules

pg_dump_anon -h HOSTIP -p 5432 -d DATABASE_NAME -U analyst_ro --table=secure_schema.user_details --file=user_details_anonysms.sql

加密数据

虽然您可以遮盖个人身份信息,但该信息会以纯文本形式存储在数据库中。管理员可以查看此信息。

在存储个人身份信息之前,请使用 pgcrypto 扩展程序对其进行加密。这样,只有拥有有效加密密钥的用户才能解密信息,并以纯文本形式查看它。

pgcrypto 扩展程序具有多个哈希加密函数。

哈希

“哈希”是一种单向加密函数,适用于您只需要对个人身份信息进行加密的情况。对于以哈希格式存储密码以及将用户输入的密码与哈希密码进行匹配,这是很有用的。哈希密码永远不会以纯文本形式解密。

对于零售网站示例,您可以先使用 pgcrypto 扩展程序对 Jack 的密码进行哈希处理,然后再将其存储在 user_details 表中。

--Hash passwords before storing them in the user_details table.

TRUNCATE TABLE secure_schema.user_details;
INSERT INTO secure_schema.user_details VALUES(1,'jack',34,'jack@example.com',crypt('testpassword', gen_salt('bf')));

--Match the hashed data with user entered password

SELECT id, name FROM secure_schema.user_details WHERE email_id = 'jack@example.com' AND password = crypt('testpassword', password);
 id | name
----+-----
  1 | jack

加密

使用“加密”函数对以密钥对个人身份信息进行加密。然后,用户需要此密钥来将该信息解密为纯文本。对于存储信用卡信息和银行详细信息、并以可读格式从中检索个人身份信息的应用场景,这是很有用的。

对于零售网站示例,Jack 的密码和电子邮件地址已加密。拥有加密密钥的用户可以解密此信息,并以纯文本形式查看它。对于所有其他用户,系统会显示错误消息。

--"user_acc_key" is the encryption key

TRUNCATE TABLE secure_schema.user_details;
INSERT INTO secure_schema.user_details VALUES(1,'jack',34,pgp_sym_encrypt('jack@example.com','user_acc_key'),pgp_sym_encrypt('testpassword','user_acc_key'));

--User: "admin" (queries without an encryption key)
--Data in the email_id and password columns are truncated for better
--formatting.

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id     | password
----+-------+-----+-----------------+-------------------
  1 | jack |  34 | \xc30d0407030209 | \xc30d040703028962

--User: "app_user" (queries with a valid encryption key)

SELECT name,pgp_sym_decrypt(email_id::bytea,'user_acc_key'),pgp_sym_decrypt(password::bytea,'user_acc_key') FROM secure_schema.user_details;
 name | pgp_sym_decrypt   | pgp_sym_decrypt
------+-------------------+----------------
 jack | jack@example.com  | testpassword

--If a user uses the wrong encryption key, then the following error message appears:

SELECT name,pgp_sym_decrypt(email_id::bytea,'user_bad_key'),
pgp_sym_decrypt(password::bytea,'user_bad_key') FROM secure_schema.user_details;
ERROR:  Wrong key or corrupt data

后续步骤

了解以下可用于保护个人身份信息免遭不正当访问的其他控制措施: