Patrones de Cumplimiento PHI/PII para Salud
Patrones para proteger datos de pacientes, datos de personal clínico y datos financieros en aplicaciones sanitarias. Aplicable a HIPAA (EE.UU.), DISHA (India), GDPR (UE) y protección general de datos sanitarios.
Cuándo Usarlo
- Al construir cualquier funcionalidad que toque historiales de pacientes
- Al implementar control de acceso o autenticación para sistemas clínicos
- Al diseñar esquemas de bases de datos para datos sanitarios
- Al construir APIs que devuelvan datos de pacientes o personal clínico
- Al implementar pistas de auditoría o registro de actividad
- Al revisar código en busca de vulnerabilidades de exposición de datos
- Al configurar Seguridad a Nivel de Fila (RLS) para sistemas sanitarios multi-institucionales
Cómo Funciona
La protección de datos sanitarios opera en tres capas: clasificación (qué es sensible), control de acceso (quién puede verlo) y auditoría (quién lo vio).
Clasificación de Datos
PHI (Información de Salud Protegida) — cualquier dato que pueda identificar a un paciente Y esté relacionado con su salud: nombre del paciente, fecha de nacimiento, dirección, teléfono, correo electrónico, números de identificación nacional (SSN, Aadhaar, número NHS), números de historia clínica, diagnósticos, medicamentos, resultados de laboratorio, imágenes, detalles de pólizas y reclamaciones de seguros, registros de citas y admisiones, o cualquier combinación de lo anterior.
PII (Datos no sensibles de pacientes) en sistemas sanitarios: datos personales del personal clínico/administrativo, estructuras de honorarios de médicos y montos de pagos, salarios y datos bancarios de empleados, información de pagos a proveedores.
Control de Acceso: Seguridad a Nivel de Fila
ALTER TABLE pacientes ENABLE ROW LEVEL SECURITY;
-- Limitar acceso por institución
CREATE POLICY "personal_lee_propia_institucion"
ON pacientes FOR SELECT TO authenticated
USING (institucion_id IN (
SELECT institucion_id FROM asignaciones_personal
WHERE usuario_id = auth.uid() AND rol IN ('medico','enfermero','tec_lab','admin')
));
-- Registro de auditoría: solo inserción (a prueba de manipulaciones)
CREATE POLICY "auditoria_solo_insertar" ON registro_auditoria FOR INSERT
TO authenticated WITH CHECK (usuario_id = auth.uid());
CREATE POLICY "auditoria_no_modificar" ON registro_auditoria FOR UPDATE USING (false);
CREATE POLICY "auditoria_no_eliminar" ON registro_auditoria FOR DELETE USING (false);
Pista de Auditoría
Cada acceso o modificación de PHI debe registrarse:
interface EntradaAuditoria {
timestamp: string;
usuario_id: string;
paciente_id: string;
accion: 'crear' | 'leer' | 'actualizar' | 'eliminar' | 'imprimir' | 'exportar';
tipo_recurso: string;
recurso_id: string;
cambios?: { antes: object; despues: object };
direccion_ip: string;
sesion_id: string;
}
Vectores de Filtración Comunes
Mensajes de error: Nunca incluir datos identificativos del paciente en mensajes de error enviados al cliente. Registrar los detalles solo en el servidor.
Salida de consola: Nunca registrar objetos completos de pacientes. Usar identificadores internos opacos (UUID) — no números de historia clínica, identificaciones nacionales o nombres.
Parámetros URL: Nunca colocar datos identificativos del paciente en cadenas de consulta o segmentos de ruta que puedan aparecer en registros o el historial del navegador. Usar solo UUID opacos.
Almacenamiento del navegador: Nunca almacenar PHI en localStorage o sessionStorage. Mantener PHI solo en memoria, obtener bajo demanda.
Claves de rol de servicio: Nunca usar la clave service_role en código del lado del cliente. Usar siempre la clave anónima/publicable y dejar que RLS aplique el control.
Registros y monitoreo: Nunca registrar registros completos de pacientes. Usar solo identificadores opacos (no números de historia clínica). Sanitizar trazas de pila antes de enviar a servicios de seguimiento de errores.
Etiquetado de Esquema de Base de Datos
Marcar columnas PHI/PII a nivel de esquema:
COMMENT ON COLUMN pacientes.nombre IS 'PHI: nombre_paciente';
COMMENT ON COLUMN pacientes.fecha_nac IS 'PHI: fecha_nacimiento';
COMMENT ON COLUMN pacientes.aadhaar IS 'PHI: id_nacional';
COMMENT ON COLUMN pagos_medicos.monto IS 'PII: financiero';
Lista de Verificación de Despliegue
Antes de cada despliegue:
- Sin PHI en mensajes de error o trazas de pila
- Sin PHI en console.log/console.error
- Sin PHI en parámetros URL
- Sin PHI en almacenamiento del navegador
- Sin clave service_role en código del cliente
- RLS habilitado en todas las tablas PHI/PII
- Pista de auditoría para todas las modificaciones de datos
- Timeout de sesión configurado
- Autenticación de API en todos los endpoints PHI
- Aislamiento de datos entre instituciones verificado
Ejemplos
Ejemplo 1: Manejo de Errores Seguro vs Inseguro
// MALO — filtra PHI en el error
throw new Error(`Paciente ${paciente.nombre} no encontrado en ${paciente.institucion}`);
// BUENO — error genérico, detalles registrados en servidor solo con IDs opacos
logger.error('Falló búsqueda de paciente', { recordId: paciente.id, institucionId });
throw new Error('Registro no encontrado');
Ejemplo 2: Política RLS para Aislamiento Multi-Institucional
-- El médico de la Institución A no puede ver pacientes de la Institución B
CREATE POLICY "aislamiento_institucion"
ON pacientes FOR SELECT TO authenticated
USING (institucion_id IN (
SELECT institucion_id FROM asignaciones_personal WHERE usuario_id = auth.uid()
));
-- Prueba: iniciar sesión como medico-institucion-a, consultar pacientes de institucion-b
-- Resultado esperado: 0 filas devueltas
Ejemplo 3: Registro Seguro
// MALO — registra datos identificables del paciente
console.log('Procesando paciente:', paciente);
// BUENO — registra solo ID interno opaco
console.log('Procesando registro:', paciente.id);
// Nota: incluso paciente.id debe ser un UUID opaco, no un número de historia clínica