Protected Health Information (PHI) and Personally Identifiable Information (PII) compliance patterns for healthcare applications. Covers data classification, access control, audit trails, encryption, and common leak vectors.
醫療 PHI/PII 合規模式
保護醫療應用程式中病人資料、臨床人員資料與財務資料的模式。適用於 HIPAA(美國)、DISHA(印度)、GDPR(歐盟)及一般醫療資料保護。
使用時機
- 建置任何涉及病人記錄的功能
- 為臨床系統實作存取控制或身分驗證
- 設計醫療資料的資料庫結構
- 建置回傳病人或臨床人員資料的 API
- 實作稽核軌跡或記錄
- 審查程式碼以找出資料暴露漏洞
- 為多租戶醫療系統設定列層級安全性 (RLS)
運作方式
醫療資料保護分為三層:分類(哪些是敏感資料)、存取控制(誰可以查看)以及稽核(誰確實查看過)。
資料分類
PHI(受保護健康資訊) — 任何可識別病人身份且與其健康相關的資料:病人姓名、出生日期、地址、電話、電子郵件、國家身分證號碼(SSN、Aadhaar、NHS 號碼)、病歷號碼、診斷、用藥、檢驗結果、影像、保險單與理賠詳細資料、預約與入院記錄,或上述任何組合。
PII(非病人敏感資料) 在醫療系統中:臨床人員/員工個人詳細資料、醫師費用結構與支付金額、員工薪資與銀行詳細資料、廠商付款資訊。
存取控制:列層級安全性
ALTER TABLE patients ENABLE ROW LEVEL SECURITY;
-- 按機構限定存取範圍
CREATE POLICY "staff_read_own_facility"
ON patients FOR SELECT TO authenticated
USING (facility_id IN (
SELECT facility_id FROM staff_assignments
WHERE user_id = auth.uid() AND role IN ('doctor','nurse','lab_tech','admin')
));
-- 稽核記錄:僅可插入(防竄改)
CREATE POLICY "audit_insert_only" ON audit_log FOR INSERT
TO authenticated WITH CHECK (user_id = auth.uid());
CREATE POLICY "audit_no_modify" ON audit_log FOR UPDATE USING (false);
CREATE POLICY "audit_no_delete" ON audit_log FOR DELETE USING (false);
稽核軌跡
每次 PHI 存取或修改都必須記錄:
interface AuditEntry {
timestamp: string;
user_id: string;
patient_id: string;
action: 'create' | 'read' | 'update' | 'delete' | 'print' | 'export';
resource_type: string;
resource_id: string;
changes?: { before: object; after: object };
ip_address: string;
session_id: string;
}
常見洩漏途徑
錯誤訊息: 切勿在傳送給用戶端的錯誤訊息中包含可識別病人的資料。詳細資訊僅記錄在伺服器端。
主控台輸出: 切勿記錄完整的病人物件。使用不透明的內部記錄 ID(UUID)— 而非病歷號碼、國家身分證號碼或姓名。
URL 參數: 切勿在查詢字串或路徑片段中放入可識別病人的資料,這些資料可能出現在記錄或瀏覽器歷史記錄中。僅使用不透明的 UUID。
瀏覽器儲存: 切勿在 localStorage 或 sessionStorage 中儲存 PHI。僅將 PHI 保留在記憶體中,按需擷取。
服務角色金鑰: 切勿在用戶端程式碼中使用 service_role 金鑰。一律使用 anon/publishable 金鑰,並讓 RLS 強制執行存取控制。
記錄與監控: 切勿記錄完整的病人記錄。僅使用不透明的記錄 ID(而非病歷號碼)。在傳送至錯誤追蹤服務前,清理堆疊追蹤。
資料庫結構標記
在結構層級標記 PHI/PII 欄位:
COMMENT ON COLUMN patients.name IS 'PHI: patient_name';
COMMENT ON COLUMN patients.dob IS 'PHI: date_of_birth';
COMMENT ON COLUMN patients.aadhaar IS 'PHI: national_id';
COMMENT ON COLUMN doctor_payouts.amount IS 'PII: financial';
部署檢查清單
每次部署前:
- 錯誤訊息或堆疊追蹤中無 PHI
- console.log/console.error 中無 PHI
- URL 參數中無 PHI
- 瀏覽器儲存中無 PHI
- 用戶端程式碼中無 service_role 金鑰
- 所有 PHI/PII 資料表已啟用 RLS
- 所有資料修改皆有稽核軌跡
- 已設定工作階段逾時
- 所有 PHI 端點皆有 API 身分驗證
- 已驗證跨機構資料隔離
範例
範例 1:安全與不安全的錯誤處理
// 不好 — 在錯誤中洩漏 PHI
throw new Error(`Patient ${patient.name} not found in ${patient.facility}`);
// 好 — 通用錯誤,詳細資訊在伺服器端僅使用不透明 ID 記錄
logger.error('Patient lookup failed', { recordId: patient.id, facilityId });
throw new Error('Record not found');
範例 2:多機構隔離的 RLS 政策
-- A 機構的醫師無法看到 B 機構的病人
CREATE POLICY "facility_isolation"
ON patients FOR SELECT TO authenticated
USING (facility_id IN (
SELECT facility_id FROM staff_assignments WHERE user_id = auth.uid()
));
-- 測試:以 facility-a 醫師身分登入,查詢 facility-b 的病人
-- 預期:回傳 0 行
範例 3:安全記錄
// 不好 — 記錄可識別的病人資料
console.log('Processing patient:', patient);
// 好 — 僅記錄不透明的內部記錄 ID
console.log('Processing record:', patient.id);
// 注意:即使是 patient.id 也應使用不透明的 UUID,而非病歷號碼






