資料隱私權是指保護個人識別資訊 (PII) 等資料,避免未經授權的人員存取。本頁面說明幾種資料隱私權做法,可保護 Cloud SQL 中的 PII。
您可以使用 Cloud SQL 安全地儲存 PII。您希望確保這項資訊在處理時受到最高層級的隱私保護,以免不慎外洩。舉例來說,如果您在資料庫中儲存信用卡資訊或醫療保健資料,可以使用 Cloud SQL 隱藏或遮蓋 PII,避免無權限的使用者看到。
請採用下列策略,保護 Cloud SQL 中的 PII:
資料欄層級的安全防護機制
資料欄層級安全性可限制哪些使用者能查看資料庫資料表中特定資料欄的內容。資料欄層級權限適用於 INSERT、UPDATE、SELECT 和 REFERENCES 陳述式。
舉例來說,假設您想在零售網站上管理兩位使用者 (Jack 和 Alice) 的 PII。
--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 在這些資料欄中的 PII。
您也可以使用單一 GRANT 陳述式合併不同權限。
GRANT SELECT (id,name,age), UPDATE (name) ON secure_schema.user_details TO analyst_ro;
以 View 為基礎的方法
您也可以在資料表上建立檢視表,排除或遮蓋要對其他使用者隱藏的資料欄,並提供檢視表的存取權 (而非資料表的存取權),藉此達到資料欄層級安全性。
以下範例說明如何使用檢視表方法,為零售網站保護 Jack 和 Alice 的 PII:
--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
在這個範例中,系統會為檢視表建立獨立結構定義,讓檢視表名稱與資料表名稱相同。如果採用以 View 為基礎的方法,您可以使用 SELECT *。
您也可以建立檢視表並遮蓋資料庫資料表的資料欄,讓未獲授權的使用者無法查看遮蓋的 PII。
CREATE OR REPLACE 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 | *****
資料列層級安全性
資料欄層級安全防護機制和檢視表做法,可讓您對特定使用者隱藏資料庫資料表資料欄中的 PII。不過,有時您可能想篩選這些資料,並授予資料表特定資料列的存取權。這個表格包含 PII,只有符合條件的使用者才能存取。這就是所謂的資料列層級安全性。
資料列層級安全性適用於多用戶群應用程式,使用者僅具備自身 PII 的讀取和寫入權限。在 Cloud SQL 中,資料表可設有資料列層級安全性政策,限制使用者可透過建立查詢來查看哪些資料列,或透過執行資料修改指令來插入、更新或刪除哪些資料列。
以零售網站為例,您可以為 Jack 和 Alice 導入資料列層級安全性,讓每位使用者只能存取自己的 PII。
--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 資料庫中的 PII 或商業機密資料。
相較於以 View 為基礎的方法,使用擴充功能有以下好處:
您可以使用各種遮蓋函式,例如替代、隨機化、偽造、假名化、部分混淆、隨機排序、加入雜訊和一般化。
您可以產生有意義的遮蓋資料,用於功能測試和資料處理。
您可以使用 PostgreSQL 資料定義語言 (DDL) 宣告遮蓋規則,並在資料表定義中指定去識別化策略。
安裝及設定 postgresql_anonymizer 擴充功能
如要在 Cloud SQL 執行個體上使用這項擴充功能,請完成下列步驟:
編輯執行個體,然後將
cloudsql.enable_anon旗標設為on。如要瞭解如何設定旗標,以及查看擴充功能支援的旗標,請參閱「設定資料庫旗標」。如果您打算使用動態遮罩,且要遮罩的資料表不在
public結構定義中,請將anon.sourceschema旗標設為包含這些資料表的結構定義名稱。在本頁的範例中,請將旗標設為secure_schema。執行下列指令,在資料庫中建立擴充功能:
--Connect to the PostgreSQL database CREATE EXTENSION IF NOT EXISTS anon CASCADE; SELECT anon.init();
安裝並設定擴充功能後,請在執行個體上使用該功能,實作動態遮蓋、靜態遮蓋和匿名轉儲去識別化策略。
動態遮罩
使用動態遮罩,為特定使用者定義遮罩規則。這些使用者無法查看 PII。而是會看到遮蓋的資料。其他使用者則會看到未遮蓋的資料。在正式環境中,如果您不想修改 PII,只想對特定使用者隱藏,這個方法就很實用。
以零售網站為例,您可以實作動態遮罩,讓管理員查看 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)';
--Verify that the masked user is configured. The search_path must include
--the mask schema followed by the schema set in the anon.sourceschema flag.
SELECT rolconfig FROM pg_roles WHERE rolname = 'analyst_ro';
rolconfig
--------------------------------------
{"search_path=mask, secure_schema"}
--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" (open a new connection; 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 user_details;
id | name | age | email_id | password
----+-------+-----+------------------------+-----------------
1 | jack | 34 | alisontodd@example.com | 13d249f2cb4127b
2 | alice | 37 | amanda35@example.com | 13d249f2cb4127b
--The masked user can't query the source table directly.
SELECT * FROM secure_schema.user_details;
ERROR: permission denied for schema secure_schema
啟動動態遮蓋功能時,擴充功能會為 anon.sourceschema 旗標設定的結構定義中的每個資料表,在 mask 結構定義中建立檢視表。將角色標示為 MASKED 時,擴充功能會執行下列操作:
- 撤銷直接授予來源結構定義角色的權限。
- 將
mask結構定義的USAGE權限,以及其中每個檢視表的SELECT權限授予角色,包括該角色先前無法查詢的資料表檢視表。 - 將角色的
search_path設為mask結構定義,後面接著來源結構定義。
只有在查詢資料表時未指定結構定義名稱,系統才會將名稱解析為 mask 結構定義中的檢視表,並向遮蓋使用者顯示遮蓋資料。指定結構定義名稱 (例如 SELECT * FROM secure_schema.user_details) 的查詢會略過 mask 結構定義,並因權限錯誤而失敗。search_path 設定會在使用者連線時套用,因此在您為角色加上標籤後,遮罩使用者必須開啟新的連線。
靜態遮罩
使用靜態遮罩,根據遮罩規則中定義的條件,移除資料表中的 PII,並將這項資訊替換為遮罩資料。使用者無法擷取去遮罩的資料。在測試環境中,如果您想修改 PII,且不希望任何使用者查看這項資訊,這個方法就非常實用。
以零售網站為例,您可以實作靜態遮罩,讓所有使用者都無法查看 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 | 13d249f2cb4127b
2 | alice | 37 | annebenitez@example.com | 13d249f2cb4127b
匿名傾印
使用匿名傾印,將遮蓋的資料匯出至 SQL 檔案。以零售網站為例,您可以為 user_details 資料表中的遮蓋資料建立 dump 檔案。
--Launch pg_dump_anon to apply earlier defined masking rules. pg_dump_anon
--reads the source table directly, so connect as a user that has the SELECT
--privilege on the table and that isn't labeled as MASKED.
pg_dump_anon -h HOSTIP -p 5432 -d DATABASE_NAME -U admin --table=secure_schema.user_details --file=user_details_anonymized.sql
加密資料
雖然您可以遮蓋 PII,但資訊會以純文字格式儲存在資料庫中。管理員可以查看這項資訊。
請使用 pgcrypto 擴充功能,先加密 PII 再儲存。這樣一來,只有具備有效加密金鑰的使用者才能解密資訊,並以純文字形式查看。
雜湊
雜湊是一種單向加密函式,只會加密 PII。這項功能適合用於以雜湊格式儲存密碼,並將使用者輸入的密碼與雜湊密碼進行比對。雜湊密碼絕不會以純文字形式解密。
以零售網站為例,您可以使用 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
加密
使用加密函式,以金鑰加密 PII。使用者需要這組金鑰,才能將資訊解密為純文字。如果應用程式需要以可讀格式擷取 PII,這項功能就很適合用來儲存信用卡資訊和銀行詳細資料。
以零售網站為例,小傑的密碼和電子郵件地址會經過加密。擁有加密金鑰的使用者可以解密這項資訊,並以純文字形式查看。其他使用者則會看到錯誤訊息。
--"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
後續步驟
請參閱下列其他控制項,瞭解如何保護 PII 免於不當存取: