PII合规模式 是做什么的?
保护医疗应用中患者数据、临床医生数据和财务数据的模式。适用于HIPAA(美国)、DISHA(印度)、GDPR(欧盟)及通用医疗数据保护。
何时使用
- 构建任何涉及患者记录的功能
- 实现临床系统的访问控制或身份验证
- 设计医疗数据的数据库架构
- 构建返回患者或临床医生数据的API
- 实现审计跟踪或日志记录
- 审查代码中的数据暴露漏洞
- 为多租户医疗系统设置行级安全(RLS)
工作原理
医疗数据保护分为三个层级:分类(哪些是敏感的)、访问控制(谁能看到)和审计(谁看到了)。
数据分类
PHI(受保护健康信息)——任何能够识别患者身份且与其健康相关的数据:患者姓名、出生日期、地址、电话、电子邮件、国家身份证号(社会安全号码、阿达尔号码、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。
浏览器存储: 切勿将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.name} 在 ${patient.facility} 未找到`);
// 正确——通用错误,详情在服务器端使用不透明ID记录
logger.error('患者查找失败', { recordId: patient.id, facilityId });
throw new Error('记录未找到');
示例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('正在处理患者:', patient);
// 正确——仅记录不透明的内部记录ID
console.log('正在处理记录:', patient.id);
// 注意:即使patient.id也应为不透明的UUID,而非病历号