医疗健康 PHI/PII 合规模式
用于在医疗健康应用中保护患者数据、临床医生数据与财务数据的模式集合。适用于 HIPAA(美国)、DISHA(印度)、GDPR(欧盟)以及一般性的医疗数据保护。
适用场景
构建任何涉及患者记录的功能
为临床系统实现访问控制或身份认证
为医疗数据设计数据库模式
构建返回患者或临床医生数据的 API
实现审计追踪或日志记录
审查代码中的数据暴露漏洞
为多租户医疗系统设置行级安全(RLS)
工作原理
医疗数据保护在三个层面上运作:分类(什么是敏感的)、访问控制(谁能看到)、审计(谁看过了)。
数据分类
PHI(受保护健康信息)——任何能够识别患者身份且与其健康相关的数据:患者姓名、出生日期、地址、电话、邮箱、国家身份证号(SSN、Aadhaar、NHS 号)、病历号、诊断、用药、检验结果、影像、保险保单与理赔明细、预约与入院记录,或以上任意组合。
医疗系统中的 PII(非患者敏感数据):临床医生/员工的个人详细信息、医生费用结构与支付金额、员工薪资与银行信息、供应商付款信息。
访问控制:行级安全(RLS)
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。
浏览器存储:切勿将 PHI 存入 localStorage 或 sessionStorage。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() ));
-- 测试:以 doctor-facility-a 登录,查询 facility-b 的患者 -- 预期:返回 0 行
示例 3:安全日志记录
// 错误做法——记录可识别患者数据 console.log('Processing patient:', patient);
// 正确做法——仅记录不透明的内部记录 ID console.log('Processing record:', patient.id); // 注意:即使是 patient.id 也应是不可逆的 UUID,而非病历号