PII 合規模式 是做什麼的?
用於保護醫療保健應用程式中病患資料、臨床醫生資料及財務資料的模式。適用於 HIPAA(美國)、DISHA(印度)、GDPR(歐盟)及一般醫療保健資料保護。
使用時機
- 建置任何涉及病患紀錄的功能
- 為臨床系統實作存取控制或驗證
- 設計醫療保健資料的資料庫結構描述
- 建置會回傳病患或臨床醫生資料的 API
- 實作稽核軌跡或記錄
- 審查程式碼中是否存在資料暴露漏洞
- 為多租戶醫療保健系統設定資料列層級安全性 (RLS)
運作方式
醫療保健資料保護運作於三個層面:分類(哪些是敏感資料)、存取控制(誰可以查看)以及稽核(誰查看了資料)。
資料分類
PHI(受保護健康資訊) — 任何能識別病患身份且與其健康相關的資料:病患姓名、出生日期、地址、電話、電子郵件、國民身分證號碼(社會安全碼、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 保存在記憶體中,按需擷取。
服務角色金鑰: 絕不在客戶端程式碼中使用服務角色金鑰。始終使用匿名/公開金鑰,並讓 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
- 用戶端程式碼中不包含服務角色金鑰
- 所有 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()
));
-- 測試:以 A 機構的醫生身份登入,查詢 B 機構的病患
-- 預期:回傳 0 行
範例 3:安全的日誌記錄
// 錯誤 — 記錄可識別的病患資料
console.log('Processing patient:', patient);
// 正確 — 僅記錄不透明的內部紀錄 ID
console.log('Processing record:', patient.id);
// 注意:即使 patient.id 也應是 UUID,而非病歷號碼