UDENTIVA Plataforma Inteligente de Gestión Dental
SEGURIDAD

Modelo de seguridad de la API

En nosotros la seguridad no es una capa añadida a posteriori, es el centro de la arquitectura. El aislamiento de datos, la separación de identidades y la escritura idempotente están grabados en la capa más profunda del código: no son un ajuste que se pueda desactivar, sino la forma en que funciona el sistema.

Aislamiento a nivel de fila Escritura idempotente Consulta parametrizada Aislamiento por loopback
Aislamiento de datos

Aislamiento a nivel de fila: fail-closed

En cada tabla con alcance de inquilino, PostgreSQL Row-Level Security FORCE está activado; la política vincula cada fila a la condición "tenant_id = current_setting('app.current_tenant')".

Una consulta que llega sin establecer el context del inquilino devuelve cero filas, ni siquiera un error, silenciosamente vacía. Ver los datos de una clínica con la sesión de otra clínica es arquitectónicamente imposible.

El test de aislamiento entre inquilinos está obligatoriamente en verde en la integración continua (CI); si está en rojo, el código no se fusiona.

Escritura atómica

Identidad local a la transacción, operación atómica

La identidad del inquilino se establece AL PRINCIPIO de la transacción en cada operación de escritura y solo es válida durante esa transacción; no se adhiere al pool de conexiones ni se filtra a otras solicitudes.

Las operaciones multientidad (factura + línea + pago + descuento de stock) son atómicas dentro de una única transacción: o se escriben todas juntas o ninguna. No se genera un registro incompleto o inconsistente.

Autorización

La autorización por roles (RBAC) se impone en el servidor

El control de autorización se realiza en la capa de la API; nunca se confía en el cliente ni en el frontend. Ocultar un menú en el navegador es solo cuestión de apariencia: la decisión real está en el servidor.

Las mutaciones del núcleo (Fase 1) están protegidas según los roles de admin, recepcionista y médico. Aunque un rol no autorizado invoque el endpoint, la solicitud se rechaza.

Protección contra repeticiones

Escritura idempotente: sin operaciones duplicadas

Cada solicitud de escritura lleva una Idempotency-Key; el bloqueo del lado del servidor impide la segunda operación que llegue con la misma clave.

Aunque la red se caiga o el cliente reenvíe la misma solicitud, no se genera un segundo cobro ni una segunda factura. El resultado es siempre único y predecible.

Seguridad de consultas

Inyección SQL imposible: consulta parametrizada

Todas las consultas a la base de datos son sentencias totalmente parametrizadas, generadas en tiempo de compilación con sqlc. En la base de código no hay una sola línea que construya SQL concatenando cadenas a mano con entrada del usuario.

Esto elimina estructuralmente toda la clase de ataques de inyección SQL: no se basa en un esfuerzo de "filtrado" o "escape", sino en la forma en que se construye la consulta.

Superficie de red

Aislamiento por loopback: el núcleo cerrado al exterior

El API central solo escucha en 127.0.0.1 (loopback). Cualquier intento de vincularse a 0.0.0.0 o a una IP pública se rechaza al inicio; el núcleo nunca se expone a internet bajo ninguna circunstancia.

La única superficie pública es una puerta ligera (BFF): no contiene lógica de negocio más allá de la sesión, el renderizado y CSRF. El navegador nunca puede ver ni direccionar el API central directamente.

Identidad y sesión

Contraseña con argon2id, clave de sesión opaca

Las contraseñas se cifran con argon2id, el estándar del sector resistente en memoria; no se utilizan hashes planos ni débiles.

Las claves de sesión son valores opacos criptográficamente aleatorios de 32 bytes, se almacenan en Redis y expiran por TTL. Al navegador solo se refleja una cookie HttpOnly + Secure + SameSite; la clave nunca se expone a JavaScript.

Auditoría

Registro de auditoría inalterable (append-only)

Las operaciones importantes se escriben en el registro de auditoría append-only dentro de la MISMA transacción que la mutación que las desencadena. Si la operación se revierte, tampoco se escribe el registro de auditoría: los dos son inseparables.

A la tabla de auditoría se le retiró el permiso de UPDATE/DELETE; los registros no pueden editarse ni eliminarse después. El pasado permanece tal cual.

Privacidad

Enmascarado de datos sensibles

El TCKN, la contraseña, la clave de sesión y los datos de salud no entran en los registros de ninguna forma. Estos campos se enmascaran incluso en las salidas de depuración.

Cuando es necesario, los campos sensibles se cifran a nivel de columna. Los datos de salud de categoría especial se protegen con reglas incorporadas al diseño desde el principio.

Integridad monetaria

Seguridad monetaria: numeric, contraasiento

El dinero se guarda en todas partes como numeric(14,2); los cálculos monetarios no se hacen con float. El redondeo ocurre en un único punto, en el servidor, de modo que no se produce desfase de céntimos ni diferencia de redondeo.

La cancelación y la devolución se procesan como un contraasiento en lugar de borrar el registro. El saldo de la cuenta no se escribe a mano; siempre se deriva de la suma de facturas y pagos. El pasado no se altera.

Transferencia

Seguridad de transporte y navegador

Todo el tráfico se transporta sobre HTTPS/TLS y HSTS está activado; el navegador establece la conexión únicamente cifrada.

Una política estricta de seguridad de contenido (CSP) bloquea los scripts inline; X-Frame-Options DENY previene el clickjacking, X-Content-Type-Options nosniff evita la confusión de tipos MIME. También se aplican Referrer-Policy y Permissions-Policy.

Importante

Separación de niveles de identidad + plano de administración separado

El usuario de clínica, el portal del paciente y el operador de plataforma son tiers de identidad SEPARADOS: encabezado propio, espacio de sesión propio. La clave de un tier no funciona en otro: los límites de autorización están rigurosamente separados.

Los endpoints de plataforma y administración (aprovisionamiento de inquilinos, facturación, gestión de automatización/complementos, generación de claves API) NO ESTÁN presentes en el API público.

Estas funciones operan en un plano de control separado, interno y con un patrón de identidad distinto (clave de administración propia); no es accesible ni descubrible desde fuera. Así, la superficie de ataque se reduce notablemente.

CÓMO FUNCIONA

Una sola transacción, aislamiento fail-closed

El siguiente flujo conceptual muestra cómo cada escritura queda bloqueada al inquilino y permanece idempotente. Es solo con fines ilustrativos.

# 1) El contexto de inquilino se establece AL PRINCIPIO de la transacción (exclusivo de esa tx)
BEGIN;
  SELECT set_config('app.current_tenant', :session_tenant_id, true);

  # 2) Bloqueo con Idempotency-Key: con la misma clave no se crea una segunda operación
  SELECT lock_idempotency(:idempotency_key);

  # 3) Escritura multi-entidad: todo atómico en una sola tx
  INSERT INTO invoices  ...;   # RLS: tenant_id cubierto automáticamente
  INSERT INTO payments  ...;
  INSERT INTO audit_log ...;   # append-only, la misma tx
COMMIT;

# Si no se establece el context, la política RLS no devuelve ninguna fila:
SELECT * FROM patients;  --> 0 fila (no un error, silenciosamente vacía)
Verificable de forma independiente

Parte de la seguridad de transporte es observable desde fuera: puede inspeccionar usted mismo el certificado HTTPS/TLS de su conexión, así como cabeceras de seguridad de respuesta como HSTS y la política de seguridad de contenido, desde las herramientas de desarrollo de su navegador. Nuestras afirmaciones se basan en controles arquitectónicos, no en frases de marketing.

¿Tiene alguna pregunta sobre la arquitectura de seguridad?
Nuestro equipo estará encantado de hablar con usted sobre los detalles técnicos y sus requisitos de cumplimiento.
Contactar