Aislamiento entre empresas: las pruebas negativas que una API multi-tenant necesita
Autenticarse como una empresa no alcanza. IDs, cursores, filtros, exports e idempotencia deben resistir intentos cruzados sin revelar ni modificar recursos de otro tenant.
Por Marco Ferreiro ·
Una API multi-tenant puede autenticar correctamente a todos sus clientes y aun así mezclar datos entre empresas. El error aparece cuando una operación confía en un identificador recibido, en una pantalla que ocultó un botón o en un filtro que alguien olvidó aplicar.
La prueba decisiva es negativa: una empresa intenta leer o modificar un recurso ficticio de otra y el sistema no sólo lo impide, sino que evita revelar si existe.
Autenticación y aislamiento responden preguntas distintas
La autenticación responde quién presenta la solicitud. La autorización decide qué puede hacer ese sujeto sobre un objeto concreto. NIST SP 800-162 describe ABAC como la evaluación de atributos del sujeto, objeto, operación y, cuando corresponde, entorno frente a una política.
En un producto para empresas, el tenant es un atributo central, pero no el único. También importan rol, estado del recurso, propósito, alcance de la credencial y operación solicitada. Un administrador de la empresa A sigue sin tener derechos sobre la empresa B.
La interfaz no es una frontera. Ocultar un enlace o reemplazar un selector no impide que alguien envíe la petición directamente.
Preparar dos universos completamente sintéticos
Creá empresa_alpha y empresa_beta en un entorno de prueba. Cada una recibe:
- usuarios con roles equivalentes;
- claves o clientes separados;
- búsquedas, vehículos y resultados ficticios;
- un export y un trabajo asíncrono;
- cursores e identificadores deliberadamente distintos;
- una misma clave de idempotencia para probar colisiones.
No uses patentes, nombres ni actas reales. El objetivo es verificar relaciones, no realismo personal. Guardá los fixtures como código para recrearlos sin depender del estado residual de una ejecución anterior.
La prueba básica: cambiar sólo el objeto
Ejecutá una lectura válida como Alpha y conservá método, ruta, parámetros y encabezados. Repetila cambiando únicamente el ID por uno perteneciente a Beta.
El resultado cruzado debe ser una denegación controlada. No debe devolver campos parciales, contar coincidencias, cargar miniaturas ni emitir eventos destinados a Beta. La misma técnica se repite para actualizar, borrar, descargar y reintentar.
OWASP destaca la autorización rota a nivel de objeto porque los IDs suelen ser controlados por el cliente. Que sean UUID difíciles de adivinar no reemplaza el control: pueden aparecer en logs, URLs, correos o relaciones.
IDs anidados y rutas engañosas
Una ruta como /empresas/alpha/reportes/reporte_beta contiene un tenant correcto y un objeto incorrecto. El servidor debe verificar que el reporte pertenece realmente a Alpha; no alcanza con autorizar el primer segmento.
Probá también:
- padre ajeno con hijo propio;
- padre propio con hijo ajeno;
- recurso movido entre estados;
- ID válido de otro tipo de objeto;
- alias histórico o ID eliminado;
- referencias incluidas dentro del cuerpo JSON.
Cada repositorio o servicio debe recibir el contexto de autorización necesario. Si el chequeo vive sólo en la ruta HTTP, un job interno podría omitirlo.
Cursores, filtros y búsquedas también son objetos
Un cursor puede codificar posición, filtros o referencias a una consulta anterior. Entregar a Alpha un cursor creado para Beta y recibir la siguiente página sería una fuga aunque los IDs directos estén protegidos.
La matriz debe intercambiar cursores, filtros guardados, tokens de descarga y enlaces firmados. También conviene probar combinaciones de include, orden y búsqueda textual: un contador total o una sugerencia autocompletada puede revelar datos sin devolver la fila.
Los caches se aíslan con claves que incorporan el tenant y todos los factores de autorización relevantes. Una respuesta cacheada para Beta nunca debe servirse a Alpha por compartir ruta pública.
Exportaciones y procesos asíncronos
Una exportación suele separarse en dos pasos: crear el trabajo y descargar el archivo. Ambos requieren autorización. Probá que Alpha no pueda consultar el estado, adivinar la ruta del objeto almacenado ni recibir la notificación de un trabajo de Beta.
En colas, el mensaje debería llevar un tenant autenticado por el servicio productor, no uno aceptado ciegamente desde el cuerpo original. El consumidor vuelve a aplicar sus invariantes antes de leer o escribir.
También revisá nombres de archivo, metadatos, métricas y trazas. La Ley 25.326 exige condiciones técnicas de integridad y seguridad para bases con datos personales; aislar salidas auxiliares forma parte de esa responsabilidad, aunque el endpoint principal sea correcto.
Idempotencia sin colisiones entre empresas
Si dos tenants usan la clave reintento-1, no deben compartir resultado. El espacio de idempotencia necesita incluir tenant, operación y, según el contrato, actor o recurso.
La prueba crea primero una operación en Beta y repite la misma clave desde Alpha con un cuerpo distinto. Un diseño correcto procesa o rechaza la solicitud según las reglas de Alpha; jamás devuelve el resultado de Beta ni considera ambas acciones idénticas.
Hacé lo mismo con webhooks, locks y deduplicación de colas. Las claves globales son un atajo peligroso cuando el cliente controla su valor.
Evitar un oráculo de existencia
Muchas APIs responden 404 para un recurso inexistente o inaccesible, aunque RFC 9110 permite distintas políticas. Lo importante es la consistencia. Compará:
- código y cuerpo;
- encabezados y tamaño;
- latencia en varias muestras;
- consumo de cuota;
- eventos de auditoría visibles al cliente;
- mensajes en tareas posteriores.
Si el recurso ajeno tarda mucho más porque el sistema primero lo carga y después niega acceso, la diferencia puede revelar existencia. La prueba fija tolerancias razonables sin exigir tiempos idénticos al microsegundo.
Qué registrar cuando una prueba falla
El reporte no debe copiar el dato ajeno que logró ver. Registrá el fixture sintético, la operación, el control esperado, la respuesta saneada y el punto donde se omitió la política. Corregí la causa común en la capa compartida antes de agregar parches ruta por ruta.
Una suite útil corre en cada cambio y genera tenants nuevos para evitar falsos positivos por caché. Su afirmación final es acotada: las fronteras probadas negaron todas las combinaciones cruzadas observadas. No reemplaza revisión de arquitectura, pero convierte el aislamiento en una propiedad comprobable.
Metodología
- Alcance
- Matriz de autorización negativa inspirada en ABAC, controles NIST y riesgos de autorización por objeto para dos tenants totalmente ficticios.
- Unidad de análisis
- Una combinación de sujeto autenticado, tenant, operación, objeto, canal de salida y resultado observable.
- Cobertura
- Lectura, escritura, búsqueda, cursores, exportaciones, trabajos asíncronos e idempotencia; estándares consultados el 14 de agosto de 2026.
Limitaciones
- La matriz no demuestra ausencia total de fallas y debe ampliarse según los recursos, roles e infraestructura de cada producto.
- Los códigos HTTP propuestos son decisiones contractuales; la propiedad esencial es no autorizar ni revelar recursos cruzados.
Fuentes
- NIST SP 800-162 — Attribute Based Access Control — National Institute of Standards and Technology (consultada el )
- NIST SP 800-53 Revision 5 — Security and Privacy Controls — National Institute of Standards and Technology (consultada el )
- Ley 25.326 de Protección de los Datos Personales — Argentina.gob.ar (consultada el )
- OWASP API1:2023 Broken Object Level Authorization — OWASP Foundation (consultada el )
- RFC 9110 — HTTP Semantics — RFC Editor (consultada el )
Preguntas frecuentes
¿Alcanza con incluir tenant_id en todas las consultas SQL?
No. Es una defensa importante, pero también deben cubrirse almacenamiento de objetos, cachés, colas, exports, jobs y cualquier autorización previa a la consulta.
¿Un 404 para recursos ajenos resuelve la filtración de existencia?
Ayuda si es consistente, pero también deben compararse cuerpo, encabezados, tiempos, métricas y efectos laterales. Una diferencia observable puede seguir funcionando como oráculo.
¿Estas pruebas pueden ejecutarse con datos de producción?
No hace falta. Dos tenants y recursos totalmente sintéticos permiten probar la frontera con menor riesgo y pueden recrearse en cada ejecución automatizada.
Notas relacionadas
Timeout no significa “sin multas”: cómo informar resultados parciales en una integración
Cuando una fuente no responde, el resultado es parcial o indeterminado, nunca cero. Un contrato explícito permite reintentar, alertar y decidir sin producir falsos negativos.
Polling de consultas sin saturar la API: Retry-After, ETag y espera con jitter
Consultar el estado cada segundo no hace que una búsqueda termine antes. Un contrato con Retry-After, ETag y una espera aleatoria reduce solicitudes repetidas, bytes y picos de clientes sincronizados.
Consultas largas en una API: cuándo responder 202 y cómo exponer el estado
HTTP 202 confirma aceptación, no finalización. Una integración útil devuelve una operación consultable, transiciones explícitas, resultado parcial y una cancelación con semántica definida.