Subdominios compartidos, dos entradas: ¿quién ve qué registros?
El subdominio elige la marca; la pertenencia verificada elige los datos. Ejecute las mismas comprobaciones de inquilino tanto si la petición llega desde una dirección de oficina como desde una VPN.
La Clínica A y la Clínica B comparten una base de código, dos subdominios y una mezcla de visitantes de oficina y por VPN. Los equipos de red suelen configurar las dos entradas por separado, y eso está bien, siempre que la aplicación no lo haga. Las comprobaciones de abajo pertenecen a la aplicación y deben comportarse igual sea cual sea la puerta que haya usado la petición.
Primero: el nombre de host solo nombra a un inquilino
Resuelva el nombre de host solicitado contra un mapeo que mantiene el administrador y rechace cualquier cosa desconocida. Use el valor de host validado del marco de trabajo en lugar de la cabecera cruda, para que un Host fabricado no pueda inyectar una clave de búsqueda. Una coincidencia correcta dice al código qué configuración de inquilino y qué marca cargar. No dice nada sobre si quien llama puede ver los datos de ese inquilino. Mantenga esa segunda pregunta en una función aparte con una entrada aparte.
Una función auxiliar compartida que devuelve a la vez el contexto y el permiso a partir de una sola búsqueda de nombre de host es el comienzo del fallo.
Segundo: la pertenencia viene de la sesión
Busque las pertenencias activas del usuario autenticado y compárelas con el inquilino de la primera comprobación. Un usuario que pertenece a ambas clínicas puede cambiar, pero el cambio debe ser una acción explícita registrada en el contexto de la petición, no una inferencia de la URL. Un usuario que pertenece a una clínica y pide la otra es denegado, también para descargas y llamadas de API.
Pruebe el caso negativo editando un identificador de registro y un parámetro de inquilino. Si cualquiera de los dos cambios devuelve datos, el alcance se lee de la petición y no de la pertenencia verificada.
El alcance de las cookies y el inicio de sesión único deciden dónde se puede presentar una cuenta. No deciden qué puede leer esa cuenta.
Tercero: la red no demuestra nada sobre la persona
Una pasarela VPN autentica un túnel, y una lista de permitidos pública autentica un rango de direcciones. Ninguna de las dos identifica a una persona. NAT agrupa a muchos usuarios en una sola dirección de origen, y un rango de oficina hace lo mismo con todos los del edificio. Trate ambos como hechos de transporte y mantenga la autorización en la aplicación, o en una integración que afirme la identidad de forma explícita y se revise como tal.
DNS es un tercer hecho de transporte. Una respuesta privada necesita una ruta privada, y un frontend público necesita una ruta de origen soportada. Ninguno de ellos lleva un permiso.
Una frase para la pared: la red decide cómo llega una petición, y la aplicación decide qué puede leer.
Cuarto: ejecute la matriz en las dos entradas
Use cuentas controladas para ejercitar A en A, B en B, A en B, un nombre de host desconocido y una cuenta autenticada sin pertenencias. La cuarta y la quinta deben fallar cerradas y nunca recurrir a un inquilino por defecto. Ejecute la misma matriz también por la entrada VPN, con un tarro de sesión por cuenta:
curl -s -o /dev/null -w '%{http_code}' -b jar.txt https://clinic-b.example.com/records/42
curl -s -o /dev/null -w '%{http_code}' -b jar.txt https://clinic-a.example.com/records/42
Luego cambie una entrada de la lista de permitidos y vuelva a ejecutar. Un resultado que se mueve significa que un control de red está tomando una decisión de autorización.
Repita la matriz después de cualquier cambio en el frontend, porque un segundo camino de código que omite la comprobación es la forma más habitual en que esta frontera se erosiona. El resultado esperado es aburrido: cada entrada produce las mismas respuestas.