- Investigacion: Anonimizacion de Lista de Medicamentos para Procesamiento Servidor
- 1. Resumen Ejecutivo
- 2. Contexto y Problema
- 3. Tecnicas de Anonimizacion
- 4. Arquitectura Propuesta
- 5. Riesgos de Re-identificacion y Mitigaciones
- 6. Implementacion Tecnica
- 6.1. Algoritmos Especificos Recomendados
- 6.1.1. Local Differential Privacy (LDP) - Randomized Response
- 6.1.2. Nota sobre Generalización Jerárquica
- 6.1.3. Supresion Basada en Frecuencia
- 6.2. Librerias y Frameworks Disponibles
- 6.2.1. Para Backend (Servidor)
- 6.2.2. Para Cliente (Movil)
- 6.3. Consideraciones de Rendimiento Movil
- 7. Validacion de Anonimato
- 8. Cumplimiento Regulatorio
- 9. Modelo de Datos para Anonimizacion
- 10. Diagrama de Arquitectura Completo
- 11. Recomendaciones de Implementacion
- 12. Referencias
- 12.1. Estandares y Normativas
- 12.2. Papers Academicos y Tecnicos
- 12.3. Herramientas y Librerias
- 12.4. Documentos MedTime Relacionados
- 12.4.1. Especificaciones de Anonimización (Serie INV-010)
- 12.4.2. Documentos de Cumplimiento y Regulaciones
- 12.4.3. Módulos Funcionales
- 12.4.4. Especificación Técnica
- 13. Glosario Especifico
Investigacion: Anonimizacion de Lista de Medicamentos para Procesamiento Servidor¶
Identificador: MTS-INV-010 Version: 1.0.0 Fecha: 2025-12-05 Autor: SpecQueen (KnowledgeDrone) Solicitado por: Director del Proyecto Estado: Completado
1. Resumen Ejecutivo¶
Esta investigacion analiza las tecnicas y arquitecturas necesarias para que MedTime pueda procesar listas de medicamentos de usuarios en el servidor para fines de enriquecimiento de base de datos, mejora del servicio y validacion de interacciones, sin poder asociar esa informacion a ningun usuario especifico.
1.1. Conclusion Principal¶
1.1.1. La anonimizacion efectiva de listas de medicamentos es viable mediante una arquitectura de separacion de identidad (NO generalizacion a categorias)¶
CONCEPTO CLAVE - SEPARACION DE IDENTIDAD: - SÍ se envían nombres específicos de medicamentos (ej: "Glucophage 850mg") - NO se envían identificadores de usuario (user_id, email, device_id, IP) - La anonimización consiste en eliminar el vínculo con la identidad, NO en generalizar datos a categorías
CONSENTIMIENTO OBLIGATORIO: Para usuarios con cuenta, el consentimiento para tratamiento de datos anonimizados esREQUISITO para usar la aplicación (no es opt-in). Ver INV-009
| Aspecto | Evaluacion | Complejidad |
|---|---|---|
| K-Anonymity para medicamentos | Parcialmente efectivo | Media |
| Differential Privacy | Altamente efectivo | Alta |
| Separacion de identidad | Esencial | Media |
| Re-identificacion por combinaciones | Riesgo Alto | Mitigable |
| Implementacion movil | Viable | Media-Alta |
| Cumplimiento regulatorio | Lograble | Media |
2. Contexto y Problema¶
2.1. Necesidades del Negocio¶
MedTime necesita procesar listas de medicamentos para:
+------------------+ +------------------+ +------------------+
| USUARIO | | SERVIDOR | | BENEFICIOS |
| | | | | |
| Lista personal |---->| Procesar datos |---->| Enriquecer BD |
| de medicamentos | | de medicamentos | | Validar interact.|
| | | | | Mejorar servicio |
+------------------+ +------------------+ +------------------+
| Caso de Uso | Descripcion | Necesidad de Identificacion |
|---|---|---|
| Enriquecer base de datos | Descubrir medicamentos nuevos o variantes | NO |
| Validar interacciones | Verificar pares de medicamentos | NO |
| Mejorar algoritmos | Entrenar modelos de adherencia | NO |
| Estadisticas agregadas | Medicamentos mas usados por region | NO |
| Detectar patrones | Combinaciones terapeuticas comunes | NO |
2.2. Requisito de Privacidad Absoluto¶
PRINCIPIO FUNDAMENTAL: El servidor DEBE poder procesar la lista de medicamentos, pero NUNCA DEBE poder asociar esa lista a un usuario especifico.
ESCENARIO IDEAL:
+----------------+ +----------------+
| Dispositivo | Datos Anonimizados | Servidor |
| Usuario #123 | ---------------------> | |
| | [Metformin, Enalapril] | NO SABE que |
| | Token: a7f2b9c3 | viene del |
| | Region: MX | Usuario #123 |
+----------------+ +----------------+
3. Tecnicas de Anonimizacion¶
3.1. K-Anonymity¶
Definicion: K-anonymity asegura que cada individuo en un dataset no puede distinguirse de al menos k-1 otros individuos respecto a los quasi-identificadores.
ANTES (k=1, identificable):
+----------+---------------+------------------------+
| Usuario | Region | Medicamentos |
+----------+---------------+------------------------+
| U001 | CDMX | [Metformin, Insulina] | <- Unico
| U002 | Monterrey | [Atorvastatina] | <- Unico
+----------+---------------+------------------------+
DESPUES (k=3, anonimizado):
+----------+---------------+------------------------+
| Grupo | Region | Medicamentos |
+----------+---------------+------------------------+
| G-A | Norte Mexico | [Antidiabeticos] | <- 3+ usuarios
| G-B | Norte Mexico | [Estatinas] | <- 3+ usuarios
+----------+---------------+------------------------+
Limitaciones para MedTime:
| Problema | Descripcion | Severidad |
|---|---|---|
| Homogeneity Attack | Si todos en un grupo tienen el mismo medicamento raro, se revela informacion | Alta |
| Background Knowledge | Atacante con info externa puede inferir identidad | Media |
| Perdida de utilidad | Generalizacion excesiva reduce valor de datos | Alta |
Aplicabilidad: PARCIAL - Util como capa complementaria, no como solucion unica.
3.2. L-Diversity¶
Definicion: L-diversity requiere que cada clase de equivalencia tenga al menos l valores bien representados para cada atributo sensible.
EJEMPLO l-diversity (l=3):
+----------+------------------------+
| Grupo | Medicamentos (diversos)|
+----------+------------------------+
| G-A | Metformin (40%) |
| | Insulina (35%) |
| | Glibenclamida (25%) | <- 3 valores diversos
+----------+------------------------+
Limitaciones:
| Problema | Descripcion |
|---|---|
| Skewness Attack | Distribucion sesgada puede revelar info |
| Similarity Attack | Valores semanticamente similares reducen privacidad |
| Complejidad | Dificil mantener diversidad con datos reales |
Aplicabilidad: LIMITADA - Dificil de aplicar a listas de medicamentos variables.
3.3. T-Closeness¶
Definicion: T-closeness requiere que la distribucion de un atributo sensible en cualquier clase de equivalencia sea cercana (distancia <= t) a la distribucion global.
DISTRIBUCION GLOBAL:
Antidiabeticos: 30%
Antihipertensivos: 25%
Estatinas: 20%
Otros: 25%
CLASE DE EQUIVALENCIA (debe ser similar):
Antidiabeticos: 32% <- |diff| = 2%
Antihipertensivos: 23% <- |diff| = 2%
Estatinas: 22% <- |diff| = 2%
Otros: 23% <- |diff| = 2%
Distancia total = 8% <= t (umbral)
Aplicabilidad: MEDIA - Util para proteger distribucion de categorias terapeuticas.
3.4. Differential Privacy (Recomendado)¶
Definicion: Differential Privacy garantiza que la probabilidad de cualquier output del proceso de anonimizacion no cambia "significativamente" si se agrega o elimina un individuo del dataset.
FORMULA:
Pr[M(D) = O] <= e^epsilon * Pr[M(D') = O]
Donde:
- M: Mecanismo de privacidad
- D: Dataset original
- D': Dataset sin un individuo
- epsilon: Parametro de privacidad (menor = mas privado)
- O: Output observado
Mecanismos para MedTime:
| Mecanismo | Uso | Descripcion |
|---|---|---|
| Laplaciano | Conteos | Agrega ruido Laplace a conteos de medicamentos |
| Gaussiano | Promedios | Agrega ruido Gaussiano a estadisticas |
| Randomized Response | Binario | Volteo aleatorio de respuestas |
| Exponential | Seleccion | Seleccion privada de categorias |
Nota sobre Differential Privacy en MedTime:
IMPORTANTE: MedTime usaSEPARACIÓN DE IDENTIDAD como enfoque principal, NO generalización a categorías. Differential Privacy es una técnica complementaria opcional para estadísticas agregadas, pero NO se usa para transformar medicamentos específicos en categorías genéricas.
# PSEUDOCODIGO - Anonimización por Separación de Identidad
def reportar_medicamentos_anonimos(lista_medicamentos, user_context):
"""
Reporta medicamentos SIN vínculo a identidad del usuario.
El servidor SÍ ve los medicamentos específicos, pero NO sabe de quién son.
"""
# 1. MANTENER medicamentos específicos (NO generalizar)
medicamentos = [med.nombre for med in lista_medicamentos]
dosis = [med.dosis for med in lista_medicamentos]
# 2. ELIMINAR todos los identificadores de usuario
# user_context.user_id -> NO SE ENVÍA
# user_context.email -> NO SE ENVÍA
# user_context.device_id -> NO SE ENVÍA
# user_context.ip -> NO SE ENVÍA
# 3. Generalizar solo metadata de contexto
region = generalizar_region(user_context.region) # "CDMX" -> "Centro"
periodo = generalizar_timestamp(now()) # "2025-12-05" -> "2025-12"
# 4. Generar token efímero no vinculado
session_token = random_bytes(32) # Nuevo cada sesión
return {
"session_token": session_token,
"medicamentos": medicamentos, # ["Glucophage 850mg", "Enalapril 10mg"]
"dosis": dosis,
"region": region,
"periodo": periodo
# SIN user_id, email, device_id, IP
}
Ventajas de Differential Privacy:
| Ventaja | Descripcion |
|---|---|
| Garantia matematica | Proteccion demostrable contra cualquier atacante |
| Composicion | Multiples consultas tienen privacidad acotada |
| Post-procesamiento | Cualquier operacion posterior mantiene garantia |
| Robustez | Resistente a ataques con conocimiento auxiliar |
Aplicabilidad: ALTA - Recomendado como mecanismo principal.
3.5. Data Masking y Pseudonimizacion¶
ISO 25237:2017 - Health Informatics Pseudonymization:
"Pseudonimizacion es el proceso donde datos personales no pueden atribuirse a un sujeto especifico sin el uso de informacion adicional, siempre que dicha informacion se mantenga separada."
PSEUDONIMIZACION EN MEDTIME:
+------------------+ +------------------+ +------------------+
| Dispositivo | | Gateway | | Servidor |
| | | Anonimizador | | Procesamiento |
| user_id: U123 |---->| Elimina |---->| No tiene |
| meds: [A,B,C] | | user_id | | user_id |
| timestamp: T | | Generaliza T | | Solo datos |
+------------------+ +------------------+ +------------------+
Tecnicas de Masking para Medicamentos:
| Tecnica | Aplicacion | Ejemplo |
|---|---|---|
| Generalizacion | Reducir especificidad | "Metformin 850mg" -> "Antidiabetico oral" |
| Supresion | Eliminar datos raros | Omitir medicamentos con <1000 usuarios globales |
| Tokenizacion | Reemplazar con tokens | "Metformin" -> "MED_CAT_A_001" |
| Truncamiento | Reducir precision | "10:35:22" -> "Manana" |
| Agrupacion (Bucketing) | Agrupar valores | "5 medicamentos" -> "3-7 medicamentos" |
4. Arquitectura Propuesta¶
4.1. Principio de Separacion de Identidad¶
+-----------------------------------------------------------------------+
| ARQUITECTURA DE ANONIMIZACION |
+-----------------------------------------------------------------------+
| |
| +------------------+ +------------------+ |
| | CAPA IDENTIDAD | | CAPA DATOS | |
| | (Dispositivo) | | (Servidor) | |
| +------------------+ +------------------+ |
| | - user_id | BARRERA DE | - tokens_sesion | |
| | - email | SEPARACION | - categorias_med | |
| | - nombre | ================> | - regiones_gen | |
| | - meds_reales | IRREVERSIBLE | - timestamps_gen | |
| +------------------+ +------------------+ |
| |
| La identidad NUNCA cruza la barrera. Los datos llegan sin origen. |
+-----------------------------------------------------------------------+
4.2. Tokens de Sesion Desvinculados¶
Problema: Si usamos tokens fijos por usuario, multiples envios del mismo usuario son correlacionables.
Solucion: Tokens de sesion efimeros, no vinculados a identidad:
GENERACION DE TOKEN ANONIMO:
Dispositivo:
1. session_id = random_bytes(32) // Nuevo cada sesion
2. NO incluir user_id, device_id, ni derivados
3. Token valido solo para esta transmision
Servidor:
- Recibe session_id efimero
- NO puede correlacionar con envios anteriores del mismo usuario
- Procesa datos y descarta session_id
Implementacion:
// PSEUDOCODIGO - Cliente (Dispositivo)
async function enviarDatosAnonimos(listaMedicamentos) {
// 1. Generar token efimero (no vinculado a usuario)
const sessionToken = crypto.randomBytes(32).toString('hex');
// 2. Anonimizar datos localmente
const datosAnonimos = {
session_token: sessionToken, // Efimero, no rastreable
categorias: generalizarMedicamentos(listaMedicamentos),
region: generalizarRegion(usuario.region), // "CDMX" -> "Centro"
rango_edad: generalizarEdad(usuario.edad), // 45 -> "40-50"
timestamp: generalizarTimestamp(Date.now()) // "Diciembre 2025"
};
// 3. NO incluir ningun identificador de usuario
// datosAnonimos.user_id = ... // PROHIBIDO
return await enviarAServidor('/api/v1/analytics/anonymous', datosAnonimos);
}
4.3. Agregacion Antes de Transmision¶
Concepto: Agregar datos de multiples usuarios en el dispositivo antes de enviar, haciendo imposible distinguir contribuciones individuales.
OPCION A: Agregacion por Batches Locales (Single User)
+-------------------+
| Dispositivo |
| Usuario U1 |
+-------------------+
| Dia 1: [Med A] |
| Dia 2: [Med A,B] | --Batch semanal--> {categorias: {cat_A: 7, cat_B: 3}}
| Dia 7: [Med A,B] |
+-------------------+
OPCION B: Secure Aggregation (Multi-User) - Avanzado
+-------------------+ +-------------------+ +-------------------+
| Dispositivo U1 | | Dispositivo U2 | | Dispositivo U3 |
| vector: [1,0,1] | | vector: [1,1,0] | | vector: [0,1,1] |
+-------------------+ +-------------------+ +-------------------+
| | |
+------------------------+------------------------+
|
Agregacion Segura
|
v
Servidor recibe: [2, 2, 2]
(suma, sin ver individuales)
4.4. Flujo de Datos Anonimizados Completo¶
sequenceDiagram
participant D as Dispositivo
participant A as Modulo Anonimizador (Local)
participant S as Servidor MedTime
participant P as Procesador Analitico
Note over D: Usuario tiene: Metformin 850mg, Enalapril 10mg
D->>A: Lista de medicamentos del usuario
Note over A: PASO 1: SEPARACIÓN DE IDENTIDAD (NO generalización)
A->>A: Mantener "Metformin 850mg" (SÍ se envía específico)
A->>A: Mantener "Enalapril 10mg" (SÍ se envía específico)
Note over A: PASO 2: Eliminar TODOS los identificadores
A->>A: Eliminar user_id, device_id, IP, email
A->>A: Generalizar timestamp: "2025-12-05 10:30" -> "2025-12"
A->>A: Generalizar region: "CDMX" -> "Centro Mexico"
Note over A: PASO 3: Generar token efímero
A->>A: session_token = random(32 bytes)
A->>A: Token NO vinculado a usuario, nuevo cada sesión
A->>S: Enviar paquete anonimizado
Note right of S: {session: "a7f2...", medicamentos: ["Metformin 850mg", "Enalapril 10mg"], region: "centro_mx", periodo: "2025-12"}
S->>P: Procesar para enriquecer catálogos
Note over P: Servidor SÍ sabe:<br/>- Medicamentos específicos usados<br/>- Dosis exactas<br/>- Región generalizada<br/>- Período (mes/año)<br/><br/>Servidor NO sabe:<br/>- Quién es el usuario<br/>- user_id, email, device_id<br/>- IP, timestamps exactos<br/>- Historial del usuario
4.5. Batch Processing para Evitar Correlacion Temporal¶
Problema: Si el servidor recibe datos en tiempo real, puede correlacionar por timestamp.
Solucion: Procesamiento por lotes con retrasos aleatorios.
MECANISMO DE BATCHING:
Dispositivo:
1. Acumular eventos localmente (24-168 horas)
2. Seleccionar momento aleatorio para envio
3. Agregar jitter: delay_random(0, 6 horas)
4. Enviar batch completo
Resultado:
- Usuario cambia medicamento el Lunes 10:00
- Servidor recibe el dato entre Martes y Domingo
- Imposible correlacionar evento con momento exacto
# PSEUDOCODIGO - Batch Processing
class BatchAnonymizer:
def __init__(self):
self.batch = []
self.batch_window_hours = 72 # 3 dias
self.jitter_max_hours = 6
def agregar_evento(self, evento_medicamento):
# Almacenar localmente (cifrado)
evento_generalizado = self.generalizar(evento_medicamento)
self.batch.append(evento_generalizado)
# Verificar si es momento de enviar
if self.debe_enviar():
self.enviar_batch()
def debe_enviar(self):
# Enviar cuando:
# - Batch tiene >= 10 eventos, O
# - Han pasado >= 72 horas desde primer evento
# - Agregar jitter aleatorio
return (
len(self.batch) >= 10 or
self.horas_desde_primer_evento() >= self.batch_window_hours
)
async def enviar_batch(self):
# Agregar delay aleatorio para decorrelacionar
jitter = random.uniform(0, self.jitter_max_hours * 3600)
await asyncio.sleep(jitter)
# Enviar batch anonimizado
await self.enviar_a_servidor(self.batch)
self.batch = []
5. Riesgos de Re-identificacion y Mitigaciones¶
5.1. Combinaciones Unicas de Medicamentos¶
Riesgo ALTO: Ciertas combinaciones de medicamentos son muy raras y pueden identificar individuos.
EJEMPLO DE RIESGO:
Usuario toma: [Imatinib, Trastuzumab, Letrozol]
Problemas:
1. Combinacion sugiere cancer de mama HER2+ con LMC
2. Solo 0.001% de usuarios tendrian esta combinacion
3. Con 1 millon de usuarios = ~10 personas
4. Con region + edad, podria ser unico
ATACANTE CON CONOCIMIENTO PREVIO:
"Se que Maria tiene cancer de mama y LMC"
+ "Datos anonimos muestran combinacion rara en Monterrey, mujer 50-60"
= Alta probabilidad de identificar a Maria
Mitigaciones:
| Mitigacion | Implementacion | Efectividad |
|---|---|---|
| Supresion de raros | No reportar combinaciones con <1000 usuarios globales | Alta |
| Generalizacion agresiva | [Imatinib, Trastuzumab] -> [Antineoplasico, Antineoplasico] | Alta |
| Ruido DP | Agregar medicamentos "falsos" con probabilidad p | Alta |
| Agregacion temporal | Solo reportar despues de N dias | Media |
Implementacion Recomendada:
# PSEUDOCODIGO - Supresion de Combinaciones Raras
def filtrar_combinaciones_raras(medicamentos, umbral_k=1000):
"""
Suprime medicamentos que harian la combinacion rara.
"""
# Consultar estadisticas globales (precalculadas, anonimas)
freq_global = obtener_frecuencias_globales()
# Ordenar medicamentos por rareza (menos frecuente primero)
meds_ordenados = sorted(medicamentos,
key=lambda m: freq_global.get(m, 0))
# Construir combinacion incrementalmente
combinacion_segura = []
for med in meds_ordenados:
combinacion_tentativa = combinacion_segura + [med]
# Verificar si combinacion es suficientemente comun
if frecuencia_combinacion(combinacion_tentativa, freq_global) >= umbral_k:
combinacion_segura = combinacion_tentativa
else:
# Suprimir este medicamento (muy raro)
log_supresion(med, "combinacion_rara")
return combinacion_segura
5.2. Patrones Temporales¶
Riesgo MEDIO: La secuencia de cambios en medicamentos puede ser unica.
EJEMPLO:
Semana 1: Agrega Metformin
Semana 3: Agrega Atorvastatina
Semana 5: Quita Metformin, agrega Insulina
Semana 8: Agrega Aspirina
Esta secuencia especifica puede ser unica entre usuarios.
Mitigaciones:
| Mitigacion | Descripcion |
|---|---|
| Solo estados, no cambios | Reportar lista actual, no deltas |
| Agregacion temporal | Reportar solo mensual/trimestral |
| Jitter en timestamps | Agregar ruido a fechas |
| Eliminacion de orden | Reportar conjuntos, no secuencias |
5.3. Correlacion con Otros Datos¶
Riesgo MEDIO: Datos externos pueden correlacionarse con datos anonimizados.
VECTORES DE CORRELACION:
+-------------------+ +-------------------+ +-------------------+
| Datos MedTime | | Datos Externos | | Correlacion |
| Anonimos | | (Atacante) | | Potencial |
+-------------------+ +-------------------+ +-------------------+
| Region: Centro MX | + | Registro civil | = | Poblacion reducida |
| Edad: 50-60 | + | Lista de pacientes | = | Match potencial |
| Categoria: IECA | + | Historial clinico | = | Identificacion |
+-------------------+ +-------------------+ +-------------------+
Mitigaciones:
| Mitigacion | Implementacion |
|---|---|
| K-anonymity como capa | Asegurar grupos >= 1000 usuarios |
| No reportar combinaciones de quasi-identifiers | Region + edad + categoria = suprimido |
| Generalizacion jerarquica | "CDMX" -> "Centro" -> "Mexico" |
5.4. Tabla de Riesgos y Mitigaciones¶
| Riesgo | Probabilidad | Impacto | Mitigacion Principal | Mitigacion Secundaria |
|---|---|---|---|---|
| Combinacion unica de meds | Alta | Alto | Supresion de raros | Generalizacion a categorias |
| Medicamento muy raro | Alta | Alto | Umbral k=1000 | No reportar |
| Patron temporal | Media | Medio | Solo estados actuales | Agregacion mensual |
| Correlacion externa | Media | Alto | K-anonymity complementario | No enviar quasi-identifiers |
| Inferencia por volumen | Baja | Bajo | Ruido DP en conteos | Jitter en timestamps |
| Ataque de reconstruccion | Baja | Alto | Epsilon bajo (e<1) | Limitar consultas |
6. Implementacion Tecnica¶
6.1. Algoritmos Especificos Recomendados¶
6.1.1. Local Differential Privacy (LDP) - Randomized Response¶
ALGORITMO: Randomized Response para Categorias de Medicamentos
Input:
- vector_categorias: vector binario [1,0,1,0,...] indicando categorias presentes
- epsilon: parametro de privacidad (recomendado: 1.0 - 4.0)
Output:
- vector_perturbado: vector con ruido DP
Pasos:
1. Para cada bit b en vector_categorias:
a. Calcular p = e^epsilon / (1 + e^epsilon)
b. Con probabilidad p: reportar b (valor real)
c. Con probabilidad 1-p: reportar bit aleatorio
Ejemplo con epsilon=2.0:
- p = e^2 / (1 + e^2) = 0.88
- 88% de las veces reporta valor real
- 12% de las veces reporta valor aleatorio
6.1.2. Nota sobre Generalización Jerárquica¶
NOTA IMPORTANTE: MedTimeNO USA generalización jerárquica como enfoque principal. Esta sección se incluye solo como referencia académica. El enfoque de MedTime es SEPARACIÓN DE IDENTIDAD: enviar medicamentos específicos pero SIN ningún identificador de usuario.
ENFOQUE DE MEDTIME (Separación de Identidad):
LO QUE SE ENVÍA: LO QUE NO SE ENVÍA:
+---------------------------+ +---------------------------+
| Metformin 850mg | | user_id |
| Enalapril 10mg | | email |
| Región: "Centro Mexico" | | device_id |
| Período: "2025-12" | | IP |
| session_token: <efímero> | | timestamps exactos |
+---------------------------+ +---------------------------+
El servidor VE los medicamentos específicos,
pero NO PUEDE vincularlos a ningún usuario.
La generalización jerárquica (Metformin → "Antidiabético") podría usarse como capa adicional de protección en casos de alto riesgo de re-identificación, pero NO es el enfoque estándar de MedTime.
6.1.3. Supresion Basada en Frecuencia¶
# PSEUDOCODIGO - Supresion Adaptativa
class SupresorAdaptativo:
# Frecuencias globales (actualizadas periodicamente, anonimas)
FRECUENCIAS_GLOBALES = cargar_frecuencias()
# Umbral minimo de usuarios para reportar
K_MINIMO = 1000
def suprimir_raros(self, lista_medicamentos):
"""
Elimina medicamentos que harian al usuario identificable.
"""
resultado = []
for med in lista_medicamentos:
categoria = self.generalizar_a_categoria(med)
freq = self.FRECUENCIAS_GLOBALES.get(categoria, 0)
if freq >= self.K_MINIMO:
resultado.append(categoria)
else:
# Suprimir - demasiado raro
self.log_supresion(categoria)
# Verificar combinacion completa
freq_combinacion = self.frecuencia_combinacion(resultado)
if freq_combinacion < self.K_MINIMO:
# Combinacion muy rara - generalizar mas
resultado = self.generalizar_mas(resultado)
return resultado
6.2. Librerias y Frameworks Disponibles¶
6.2.1. Para Backend (Servidor)¶
| Libreria | Lenguaje | Caracteristicas | Uso en MedTime |
|---|---|---|---|
| Google Differential Privacy | C++, Java, Go | DP de Google, alta performance | Procesamiento servidor |
| PipelineDP4j | Java/Kotlin | DP end-to-end para JVM | Backend analytics |
| OpenDP | Rust/Python | Framework academico riguroso | Validacion algoritmos |
| ARX | Java | K-anonymity, l-diversity, t-closeness, DP | Anonimizacion datasets |
6.2.2. Para Cliente (Movil)¶
| Libreria | Plataforma | Caracteristicas | Consideraciones |
|---|---|---|---|
| SwiftDP (OpenMined) | iOS/Swift | Wrapper de Google DP para iOS | Requiere Objective-C++ bridge |
| Google DP (via C++) | Android/iOS | Compilacion nativa | Alta complejidad |
| Implementacion propia LDP | Kotlin/Swift | Randomized Response es simple | Recomendado para v1.0 |
Recomendacion para MedTime v1.0:
ARQUITECTURA RECOMENDADA:
CLIENTE (Movil):
- Implementacion propia de LDP (Randomized Response)
- Generalizacion jerarquica de medicamentos
- Supresion de raros (con tabla local de frecuencias)
- Batch processing con jitter
SERVIDOR:
- ARX para validacion de k-anonymity
- Google DP / PipelineDP4j para agregaciones
- OpenDP para auditorias matematicas
6.3. Consideraciones de Rendimiento Movil¶
| Operacion | Tiempo Estimado | Impacto Bateria | Optimizacion |
|---|---|---|---|
| Generalizacion (local) | <10ms | Minimo | Tabla lookup |
| LDP Randomized Response | <5ms | Minimo | Crypto seguro |
| Supresion (con lookup) | <20ms | Bajo | Cache local |
| Batch + cifrado | <100ms | Bajo | Background task |
| Transmision (batch) | Variable | Medio | WiFi preferido |
// PSEUDOCODIGO iOS - Implementacion Eficiente
class AnonymizadorEficiente {
// Cache local de frecuencias (actualizado semanalmente)
private var cacheFrequencias: [String: Int] = [:]
// Generalizacion via lookup O(1)
private let tablaGeneralizacion: [String: String] = cargarTabla()
func anonimizar(medicamentos: [Medicamento]) -> DatosAnonimos {
// 1. Generalizar - O(n) con lookup O(1)
let categorias = medicamentos.map {
tablaGeneralizacion[$0.nombre] ?? "OTRO"
}
// 2. Suprimir raros - O(n)
let categoriasSeguras = categorias.filter {
(cacheFrequencias[$0] ?? 0) >= 1000
}
// 3. Aplicar LDP - O(n)
let vectorRuidoso = aplicarRandomizedResponse(
categorias: categoriasSeguras,
epsilon: 2.0
)
// 4. Preparar para batch
return DatosAnonimos(
categorias: vectorRuidoso,
timestamp: generalizarTimestamp(Date()),
region: generalizarRegion(usuario.region)
)
}
}
7. Validacion de Anonimato¶
7.1. Metricas para Verificar Anonimizacion Efectiva¶
| Metrica | Descripcion | Umbral Recomendado |
|---|---|---|
| k-Anonymity | Minimo de usuarios indistinguibles | k >= 1000 |
| l-Diversity | Diversidad en categorias sensibles | l >= 5 |
| Epsilon (DP) | Parametro de privacidad diferencial | epsilon <= 2.0 |
| Probabilidad re-identificacion | P(identificar individuo) | P < 0.001 |
| Information gain | Bits de informacion revelados | < 1 bit por categoria |
7.2. Framework de Auditoria¶
PROCESO DE AUDITORIA TRIMESTRAL:
1. ANALISIS DE DATOS ANONIMIZADOS
+------------------+
| Extraer muestra |
| de datos enviados|
+--------+---------+
|
v
+------------------+
| Verificar |
| k-anonymity |
| (k >= 1000) |
+--------+---------+
|
v
+------------------+
| Verificar |
| supresion de |
| raros |
+--------+---------+
2. PRUEBAS DE RE-IDENTIFICACION
+------------------+
| Simular ataques |
| con conocimiento |
| auxiliar |
+--------+---------+
|
v
+------------------+
| Medir tasa de |
| re-identificacion|
| (< 0.1%) |
+--------+---------+
3. VALIDACION MATEMATICA
+------------------+
| Verificar epsilon|
| efectivo con |
| OpenDP |
+------------------+
7.3. Pruebas de Re-identificacion¶
Metodologia de Testing:
# PSEUDOCODIGO - Prueba de Re-identificacion
def test_reidentificacion(datos_anonimizados, conocimiento_auxiliar):
"""
Simula ataque de re-identificacion.
Args:
datos_anonimizados: Dataset anonimizado a probar
conocimiento_auxiliar: Datos externos que atacante podria tener
Returns:
tasa_exito: Porcentaje de registros re-identificados
"""
exitos = 0
intentos = len(datos_anonimizados)
for registro in datos_anonimizados:
# Intentar vincular con conocimiento auxiliar
candidatos = buscar_candidatos(registro, conocimiento_auxiliar)
if len(candidatos) == 1:
# Re-identificacion exitosa (unico match)
exitos += 1
elif len(candidatos) <= 5:
# Casi exitoso (pocos candidatos)
exitos += 0.2
tasa_exito = exitos / intentos
# UMBRAL: < 0.1% tasa de exito
assert tasa_exito < 0.001, f"Tasa de re-identificacion muy alta: {tasa_exito}"
return tasa_exito
7.4. Auditorias Periodicas¶
| Tipo | Frecuencia | Responsable | Entregable |
|---|---|---|---|
| Automatizada | Continua | Sistema | Dashboard metricas |
| Interna | Mensual | Equipo Seguridad | Reporte tecnico |
| Externa | Trimestral | Auditor independiente | Certificacion |
| Regulatoria | Anual | Autoridad (INAI/OCR) | Cumplimiento |
8. Cumplimiento Regulatorio¶
8.1. Mapeo a Regulaciones¶
| Regulacion | Requisito | Como lo cumple esta arquitectura |
|---|---|---|
| HIPAA | De-identification (Safe Harbor/Expert) | Supresion de 18 identificadores + DP |
| LGPD | Anonimizacao (Art. 12) | Datos no pueden asociarse a titular |
| LFPDPPP | Disociacion (Art. 3-V) | Procedimiento irreversible |
| GDPR | Anonymisation | Datos ya no son "personales" |
| ISO 25237 | Pseudonymization requirements | Separacion de identidad |
8.2. Safe Harbor vs Expert Determination (HIPAA)¶
METODO SAFE HARBOR (18 identificadores):
+------------------+--------------------+---------------------+
| Identificador | Eliminado en | Metodo |
+------------------+--------------------+---------------------+
| Nombres | Dispositivo | No transmitido |
| Fechas | Dispositivo | Generalizado a mes |
| Telefonos | Dispositivo | No transmitido |
| Geografia | Dispositivo | Generalizado |
| ... | ... | ... |
+------------------+--------------------+---------------------+
METODO EXPERT DETERMINATION:
- Experto certifica que riesgo de re-identificacion es "muy pequeno"
- Documenta metodologia estadistica
- MedTime usa AMBOS metodos para maxima proteccion
8.3. Documentacion Requerida¶
| Documento | Contenido | Actualizacion |
|---|---|---|
| Privacy Impact Assessment (PIA) | Analisis de riesgos y mitigaciones | Anual |
| Data Processing Agreement (DPA) | Terminos de procesamiento anonimo | Inicial |
| Technical Specification | Algoritmos y parametros | Por cambio |
| Audit Trail | Logs de anonimizacion | Continuo |
| User Consent | Consentimiento para analytics | Registro |
9. Modelo de Datos para Anonimizacion¶
9.1. Estructura de Datos Anonimizados¶
// ESQUEMA - Datos Anonimizados Transmitidos
// NOTA: Se usa SEPARACIÓN DE IDENTIDAD, no generalización a categorías
interface DatosAnonimosMedicamentos {
// Token efimero (no vinculado a usuario)
session_token: string; // 32 bytes aleatorios, nuevo cada sesión
// Medicamentos ESPECÍFICOS (SÍ se envían)
medicamentos: string[]; // ["Glucophage 850mg", "Enalapril 10mg"]
dosis: string[]; // ["850mg", "10mg"]
// Metadata generalizada (protección adicional)
region_generalizada: string; // "Centro Mexico" (no ciudad exacta)
periodo: string; // "2025-12" (solo mes/año, no timestamp exacto)
// Control de calidad
version_anonimizador: string; // "1.0.0"
}
// LO QUE SÍ SE INCLUYE (anonimizado por separación de identidad):
// + medicamentos específicos (Glucophage, no "antidiabético")
// + dosis exactas
// + región generalizada
// + período (mes/año)
// LO QUE NUNCA SE INCLUYE (eliminado completamente):
// - user_id
// - device_id
// - email
// - nombre del usuario
// - timestamps exactos
// - IP
// - cualquier identificador directo o indirecto
9.2. Tabla de Frecuencias Globales (Publica)¶
// ESQUEMA - Frecuencias Globales (para cliente)
interface FrecuenciasGlobales {
version: string;
fecha_actualizacion: string;
// Frecuencias por categoria (k-anonymity)
categorias: {
[categoria: string]: {
frecuencia_global: number; // Usuarios que la usan
puede_reportar: boolean; // true si freq >= 1000
}
};
// Frecuencias de combinaciones comunes
combinaciones_comunes: {
[combinacion: string]: number; // "antidiabetico+ieca": 50000
};
}
10. Diagrama de Arquitectura Completo¶
+===========================================================================+
| ARQUITECTURA DE ANONIMIZACION MEDTIME |
+===========================================================================+
DISPOSITIVO (LOCAL)
+-------------------------------------------------------------------------+
| |
| +------------------+ +------------------+ +------------------+ |
| | Datos Usuario | | Anonimizador | | Cola de Batch | |
| | | | Local | | | |
| | user_id: U123 | | | | [dato_anon_1] | |
| | meds: [Met,Ena] |---->| 1. Generalizar |---->| [dato_anon_2] | |
| | region: CDMX | | 2. Suprimir raros| | [dato_anon_3] | |
| | edad: 47 | | 3. Aplicar LDP | | ... | |
| +------------------+ | 4. Gen token | +--------+---------+ |
| +------------------+ | |
| | |
| +------------------+ +--------v---------+ |
| | Frecuencias |<-----(Actualizar semanal)---| Gestor Batch | |
| | Globales (cache) | | | |
| +------------------+ | - Acumular 72h | |
| | - Jitter envio | |
| | - Cifrar TLS | |
| +--------+---------+ |
| | |
+-------------------------------------------------------------------------+
|
BARRERA DE ANONIMIZACION |
======================================|=======
|
v
RED (TLS 1.3)
+-------------------------------------------------------------------------+
| |
| SERVIDOR (BACKEND) |
| |
| +------------------+ +------------------+ +------------------+ |
| | API Gateway | | Validador | | Procesador | |
| | | | Anonimato | | Analytics | |
| | - Sin logs IP |---->| - Verificar k |---->| - Agregar datos | |
| | - Token efimero | | - Verificar DP | | - Entrenar ML | |
| | - No session | | - Descartar ID | | - Generar stats | |
| +------------------+ +------------------+ +--------+---------+ |
| | |
| v |
| +------------------+ +------------------+ +------------------+ |
| | Frecuencias |<----| Agregador |<----| Dataset | |
| | Actualizadas | | Estadistico | | Anonimo | |
| | (para clientes) | | (con DP) | | (sin IDs) | |
| +------------------+ +------------------+ +------------------+ |
| |
+-------------------------------------------------------------------------+
GARANTIAS (SEPARACIÓN DE IDENTIDAD):
- El servidor NUNCA recibe user_id, device_id, email, IP, ni identificadores
- El servidor SÍ recibe medicamentos específicos (Glucophage, no "antidiabético")
- El servidor SÍ recibe dosis exactas
- Cada transmision usa token efimero no correlacionable
- Región generalizada (Centro Mexico, no CDMX)
- Período generalizado (2025-12, no timestamp exacto)
- El servidor NO PUEDE vincular medicamentos a ningún usuario específico
- Consentimiento OBLIGATORIO para usuarios con cuenta (requisito de uso)
11. Recomendaciones de Implementacion¶
11.1. Para MedTime v1.0 (Separación de Identidad)¶
ENFOQUE PRINCIPAL: Separación de identidad (enviar medicamentos específicos SIN identificadores de usuario)
| Componente | Prioridad | Complejidad | Recomendacion |
|---|---|---|---|
| Eliminación de identificadores | CRÍTICA | Baja | Filtrar user_id, email, device_id, IP |
| Tokens efímeros | CRÍTICA | Baja | crypto.randomBytes(32), nuevo cada sesión |
| Generalización de región | Alta | Baja | "CDMX" → "Centro Mexico" |
| Generalización de timestamp | Alta | Baja | "2025-12-05 10:30" → "2025-12" |
| Consentimiento obligatorio | CRÍTICA | Media | Obtener durante onboarding |
| Batch processing | Media | Media | Cola local, envío diferido |
| Jitter temporal | Media | Baja | delay aleatorio en envíos |
Nota: NO se generalizan medicamentos a categorías. Se envía "Glucophage 850mg", no "Antidiabético".
11.2. Para Versiones Futuras¶
| Componente | Version | Descripcion |
|---|---|---|
| Secure Aggregation | v2.0 | Agregacion multiusuario |
| Federated Learning | v2.0 | ML sin datos centralizados |
| Verificacion formal DP | v1.5 | Prueba matematica con OpenDP |
| Auditoria externa | v1.0+ | Certificacion independiente |
11.3. Checklist de Implementacion¶
FASE 1: INFRAESTRUCTURA - SEPARACIÓN DE IDENTIDAD (v1.0)
[ ] Implementar filtro de identificadores (eliminar user_id, email, device_id, IP)
[ ] Crear generador de tokens efímeros (32 bytes, nuevo cada sesión)
[ ] Implementar generalización de región (CDMX → Centro Mexico)
[ ] Implementar generalización de timestamp (fecha → mes/año)
[ ] Implementar cola de batch local para envío diferido
[ ] Agregar jitter aleatorio al envío
FASE 2: CONSENTIMIENTO Y FLUJO (v1.0)
[ ] Implementar flujo de consentimiento OBLIGATORIO en onboarding
[ ] Integrar anonimizador en flujo de sync
[ ] Configurar API sin logs de IP
[ ] Validar que medicamentos específicos SÍ se envían
[ ] Validar que identificadores NUNCA se envían
[ ] Documentar Privacy Impact Assessment
FASE 3: VALIDACION (v1.0)
[ ] Ejecutar pruebas de re-identificación (verificar que user_id no se filtra)
[ ] Auditoria interna de código
[ ] Revision legal de cumplimiento (LFPDPPP, LGPD, HIPAA)
[ ] Pruebas de penetración
[ ] Verificar que consentimiento se obtiene correctamente
FASE 4: OPERACION (v1.0+)
[ ] Monitoreo continuo: verificar ausencia de identificadores en logs
[ ] Auditorias trimestrales de anonimización
[ ] Ajuste de proceso según regulaciones actualizadas
12. Referencias¶
12.1. Estandares y Normativas¶
- ISO 25237:2017 - Health informatics - Pseudonymization
- HIPAA De-identification Guidance
- LGPD - Lei Geral de Protecao de Dados
- LFPDPPP - Ley Federal de Proteccion de Datos Personales
12.2. Papers Academicos y Tecnicos¶
- A Study on k-anonymity, l-diversity, and t-closeness Techniques focusing Medical Data
- t-Closeness: Privacy Beyond k-Anonymity and l-Diversity
- Differential Privacy for Public Health Data
- Local Differential Privacy in the Medical Domain
- Evaluating the Risk of Re-identification from Hospital Prescription Records
- Privacy-preserving aggregation of personal health data streams
12.3. Herramientas y Librerias¶
- Google Differential Privacy Libraries
- ARX Data Anonymization Tool
- OpenDP Library
- SwiftDP by OpenMined
- PipelineDP4j
12.4. Documentos MedTime Relacionados¶
12.4.1. Especificaciones de Anonimización (Serie INV-010)¶
| Documento | Descripción | Catálogo Enriquecido |
|---|---|---|
| INV-010 (este documento) | Anonimización de medicamentos | Catálogo de Medicamentos |
| INV-011 | Anonimización de estudios y tratamientos | Catálogo de Estudios |
| INV-012 | Anonimización de interacciones med-med | Catálogo de Interacciones |
| INV-013 | Anonimización de interacciones med-estudio | Catálogo de Interacciones Med-Estudio |
| INV-014 | Anonimización de efectos secundarios | Catálogo de Efectos Adversos |
12.4.2. Documentos de Cumplimiento y Regulaciones¶
- INV-009: Consentimiento Datos de Salud
- INV-001: Cifrado E2E Zero Knowledge
- INV-005: HIPAA Security Rule
12.4.3. Módulos Funcionales¶
- MTS-PRI-001: Privacidad y Consentimiento
- MTS-CAT-001: Catálogo de Medicamentos
- MTS-MED-001: Medicamentos
- MTS-AUTH-001: Autenticación y Seguridad
12.4.4. Especificación Técnica¶
- 03-Estrategia de Datos - Sección 1.2 ANONYMIZED_DATA
13. Glosario Especifico¶
| Termino | Definicion |
|---|---|
| K-Anonymity | Propiedad donde cada registro es indistinguible de al menos k-1 otros |
| L-Diversity | Extension de k-anonymity que requiere diversidad en atributos sensibles |
| T-Closeness | Extension que requiere distribucion similar a la poblacion |
| Differential Privacy | Marco matematico que limita lo que puede inferirse de un individuo |
| Epsilon (ε) | Parametro de privacidad en DP; menor = mas privado |
| LDP | Local Differential Privacy - DP aplicado en el dispositivo |
| Randomized Response | Tecnica donde respuestas se voltean aleatoriamente |
| Quasi-identificador | Atributo que combinado puede identificar individuos |
| Re-identificacion | Proceso de vincular datos anonimos con identidad |
| Safe Harbor | Metodo HIPAA que elimina 18 identificadores especificos |
Documento generado por SpecQueen (KnowledgeDrone) - "La resistencia es futil. Tus datos seran anonimizados... perfectamente."