CodeGym /課程 /SQL SELF /在資料表和欄位層級加密資料的範例

在資料表和欄位層級加密資料的範例

SQL SELF
等級 48 , 課堂 2
開放

存在資料庫裡的資訊,對公司來說通常超級有價值。但很可惜,這些資料對壞人來說也很有吸引力。所以我們才要考慮加密——這是保護資料不被亂看的一種方法。

加密可以保護機密資訊:像是密碼、信用卡號或個人資料。它也有助於遵守各種法律規定,比如 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;

安全小撇步

  1. key 要分開存

千萬不要把對稱式 key 跟加密資料放在同一個資料庫。

  1. key 要設複雜一點

像 "123" 這種簡單 key 很容易被猜到。

  1. 定期換 key

為了防止資料外洩,建議定期換 key,然後把資料重新加密。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION