Las páginas públicas de SaaS pueden seguir abiertas para todos mientras las operaciones de administración que hay detrás rechazan a cualquiera que esté fuera de la VPN. El mecanismo que lo hace posible no es un menú oculto ni una página de inicio de sesión aparte; es una comprobación de la ruta de red que entregó la solicitud. Si te equivocas con la evidencia de la dirección, la comprobación o bien deja fuera a administradores reales o bien admite a cualquiera que sepa escribir una cabecera. Empieza por lo que el origen recibe realmente.

Lo que el origen recibe realmente tras el túnel

Cuando un navegador llega al sitio público a través de una VPN que también transporta tráfico de internet, la puerta de enlace traduce la conexión antes de que salga. El SaaS ve la dirección de salida pública de la puerta de enlace, normalmente una dirección o un rango pequeño, y nunca ve la dirección del túnel del portátil. Por eso falla añadir 10.90.0.42 a la lista de permitidos, y por eso falla todavía más fuerte añadir todo el RFC 1918: lo segundo admite todas las redes privadas que puedan alcanzarte. La única dirección que merece una condición es la que tu organización posee realmente en la salida.

curl -s https://ifconfig.me
dig +short admin.example.com

El túnel dividido rompe esa suposición en silencio. Si la VPN solo transporta rutas privadas de la oficina, la solicitud al nombre de host administrativo público sale por el proveedor local y el origen ve una dirección residencial. Un icono de VPN conectada no demuestra nada sobre este destino concreto, así que prueba el destino y no el túnel.

Detente y corrige el enrutamiento antes de escribir cualquier política si la dirección de salida varía por usuario. Una condición que solo coincide con algunos administradores es peor que ninguna condición, porque esconde el problema hasta un incidente.

Confía solo en el proxy que reescribe la dirección

La mayoría de los sitios públicos están detrás de una CDN o un proxy inverso, así que la dirección de socket del origen pertenece a esa interfaz y no al visitante. La interfaz suele reenviar la dirección original en una cabecera, y esa cabecera la controla un atacante a menos que el origen solo la acepte de proxys conocidos. Configura explícitamente la lista de fuentes de confianza y haz que el origen sea inalcanzable desde cualquier otro lugar. Sin esa segunda mitad, un atacante se salta el proxy y envía la cabecera directamente.

set_real_ip_from 192.0.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
curl -H 'X-Forwarded-For: 198.51.100.27' https://origin.example.com/admin

El mismo razonamiento se aplica al protocolo PROXY: solo es fiable cuando el oyente está ligado a una interfaz que el proxy puede alcanzar y nada más puede. Un contexto de dirección ausente debe hacer fallar la comprobación protegida en lugar de caer en un permiso por defecto. Una cabecera ausente no es evidencia de una ruta de confianza.

Ata la condición a cada operación protegida

Pon la comprobación en la frontera de autorización por la que pasa cada operación protegida, no en la página que renderiza el menú. Los grupos de rutas, el middleware o una capa de políticas funcionan todos; una copia por controlador no, porque el controlador que alguien añada el próximo trimestre no la tendrá.

user = requireAuthenticatedSession()
requirePermission(user, "admin")
requireVpnEgress(verifiedClientAddress(request))
performProtectedOperation(user, request)

La misma frontera tiene que cubrir la API JSON, las exportaciones, las URL de descarga firmadas y el apretón de manos de WebSocket, ya que ninguno de ellos necesita que se solicite primero la página HTML. Un enlace de descarga creado mientras la VPN estaba activa sigue siendo válido después a menos que el punto de descarga vuelva a comprobar. Las sesiones de larga duración también necesitan una regla de reevaluación, o una solicitud autenticada se convierte en una exención permanente. La denegación por defecto es el único ajuste que sobrevive a la rotación de personal.

Las cachés compartidas son la otra forma de rodear la comprobación. Una caché que ya contiene una respuesta protegida puede servirla sin contactar con el origen, así que marca las respuestas de administración como privadas y mantenlas fuera del almacenamiento compartido. Si una caché tiene que servirlas, la comprobación de acceso tiene que ejecutarse antes del servicio, lo que normalmente significa que no puede ser una caché compartida en absoluto.

Prueba los bypass que acabas de cerrar

Ejercita la matriz en lugar del camino feliz: un administrador por la VPN, el mismo administrador sin ella, un no administrador por ella y una cabecera de dirección falsificada. Añade una solicitud directa al origen y una solicitud con respuesta en caché, porque esas dos son las que se saltan la interfaz por completo.

curl -sI https://admin.example.com/export.csv
curl -s -H 'X-Forwarded-For: 198.51.100.27' https://origin.example.com/admin
curl -s https://admin.example.com/api/me -o /dev/null -w '%{http_code}\n'

Cada solicitud debería devolver el estado que promete la política, y el registro debería anotar qué evidencia de dirección se usó. Cubre IPv6 por separado, porque un origen de doble pila puede ver una familia de origen distinta de la que probaste. Mantén las operaciones habituales de los clientes funcionando fuera de la VPN, o el cambio se revertirá la primera vez que un cliente se queje. Escribe el resultado esperado de cada fila antes de ejecutarla, para que un aprobado sorprendente sea visible.

La dirección de salida demuestra una ruta de red permitida, no una persona ni un dispositivo gestionado. Mantenla como una condición junto a la autenticación y el permiso, y el área de administración sigue siendo estrecha sin convertir todo el producto en un servicio solo para VPN. Esa separación es el diseño, no una limitación suya.

Artículos relacionados