存在資料庫裡的資訊,對公司來說通常超級有價值。但很可惜,這些資料對壞人來說也很有吸引力。所以我們才要考慮加密——這是保護資料不被亂看的一種方法。
加密可以保護機密資訊:像是密碼、信用卡號或個人資料。它也有助於遵守各種法律規定,比如 GDPR 或 HIPAA。如果真的發生資料外洩,加密過的資料會難很多被利用,這樣損失就小很多。
PostgreSQL 有很方便的對稱式加密函式。用 pgp_sym_encrypt(data, key) 你可以把資料加密,然後用 pgp_sym_decrypt(encrypted_data, key) 和同一把 key 把它解開。很簡單,也很安全。
加密資料的範例
步驟 1:建立資料表
我們來建立一個 users 資料表,裡面有個欄位要存加密過的電話號碼:
-- 建立有加密資料欄位的資料表
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL,
phone_encrypted BYTEA -- 這裡會存加密過的電話號碼
);
步驟 2:加密後新增資料
現在我們加一個使用者,把他的電話號碼加密存進去:
-- 加密後插入資料
INSERT INTO users (username, phone_encrypted)
VALUES ('john_doe', pgp_sym_encrypt('123-456-7890', 'my_secret_key'));
注意我們用 pgp_sym_encrypt 這個函式。my_secret_key 就是我們的對稱式 key。實際上 key 要設得很複雜,而且要好好保護。
步驟 3:解密後查詢資料
要存取資料時,我們可以把它解密:
-- 解密後查詢資料
SELECT
username,
pgp_sym_decrypt(phone_encrypted, 'my_secret_key') AS phone
FROM users;
如果 key 是對的,你就會看到原本的電話號碼。
進階:在現有資料表加上加密
如果資料表已經存在,我們想開始加密其中一個欄位的資料怎麼辦?來看個例子。
步驟 1:新增欄位
假設我們有個 customers 資料表,想要加密信用卡號的欄位:
-- 新增加密資料欄位
ALTER TABLE customers ADD COLUMN card_number_encrypted BYTEA;
步驟 2:把資料加密搬到新欄位
我們把現有資料加密後搬到新欄位:
-- 加密資料並搬到新欄位
UPDATE customers
SET card_number_encrypted = pgp_sym_encrypt(card_number, 'my_other_secret_key');
步驟 3:刪除未加密欄位
加密完資料後,就可以把舊的欄位刪掉:
-- 刪除舊的未加密欄位
ALTER TABLE customers DROP COLUMN card_number;
現在資料已經被加密保護,只有有 key 的人才看得到。
操作加密資料時要注意什麼
處理加密欄位時有幾個重點:
資料型態:
- 加密後的值會用二進位格式 (
BYTEA) 存,不是人看得懂的字串。 - 查詢時要用解密函式。
搜尋和篩選:
- 不能直接用加密資料查詢,比如:
SELECT * FROM users WHERE phone_encrypted = '123-456-7890'; -- 不會動!
- 要查詢的話,可以先解密再比對:
SELECT *
FROM users
WHERE pgp_sym_decrypt(phone_encrypted, 'my_secret_key') = '123-456-7890';
效能:
加密和解密會讓查詢變慢。只在真的需要的地方用就好。
實際情境:保護密碼
存密碼是最常見的加密任務之一。千萬不要把密碼明文存(超爛的做法),應該要用雜湊。
用 pgcrypto 雜湊密碼
我們會用 crypt() 這個函式來安全雜湊密碼:
-- 插入資料時雜湊密碼
INSERT INTO users (username, phone_encrypted)
VALUES ('alice', crypt('my_secure_password', gen_salt('bf')));
這裡 gen_salt('bf') 會產生雜湊密碼用的 salt。
要驗證密碼時,比對雜湊值就好:
-- 比對雜湊密碼
SELECT username
FROM users
WHERE crypt('my_secure_password', phone_encrypted) = phone_encrypted;
安全小撇步
- key 要分開存:
千萬不要把對稱式 key 跟加密資料放在同一個資料庫。
- key 要設複雜一點:
像 "123" 這種簡單 key 很容易被猜到。
- 定期換 key:
為了防止資料外洩,建議定期換 key,然後把資料重新加密。
GO TO FULL VERSION