Hardening de red y protección perimetral
ABA da acceso directo a motores de base de datos reales a sus usuarios — eso cambia el modelo de amenazas respecto a una API web típica, y explica varias decisiones de hardening que no serían necesarias en otro tipo de proyecto.
Firewall perimetral
Solo tres puertos quedan abiertos a internet a nivel de sistema operativo: 22 (SSH), 80 y
443. Todo lo demás se deniega por defecto.
Docker escribe sus propias reglas de iptables y pasa por encima de las políticas del
firewall del sistema operativo para cualquier puerto publicado explícitamente con -p. Esto
significa que un contenedor que publica un puerto queda alcanzable desde internet aunque el
firewall del sistema operativo nunca lo haya permitido — es una de las causas más comunes de
exposición accidental en proyectos con Docker.
Esto obliga a dos estrategias distintas según el tipo de servicio:
- El backend .NET se mitiga atando su puerto únicamente a
127.0.0.1— Docker rechaza cualquier conexión que no venga de dentro del propio servidor, así que solo Nginx (que corre en la misma máquina) puede alcanzarlo. - Los motores de base de datos (SQL Server, MySQL) necesitan quedar accesibles para que los usuarios se conecten directo con sus propios clientes de escritorio (DBeaver, SSMS, etc.) — no se puede resolver atando el puerto a loopback. La protección se mueve entonces dentro del propio motor de base de datos (ver siguiente sección), consistente con el enfoque Database-Centric del proyecto: incluso la seguridad de red de las bases de datos vive en la capa de datos, no en el firewall del sistema operativo.
Protección a nivel de motor de base de datos
Como el firewall no alcanza a filtrar quién se conecta a los motores de base de datos, esa responsabilidad se implementa directamente en ellos:
- Bloqueo de operaciones destructivas. Un proxy de protocolo se ubica delante del motor MySQL
y bloquea en tránsito sentencias
DROP DATABASE/DROP SCHEMA, sin cambiar los privilegios del usuario ni la sintaxis SQL que usan los estudiantes — el mensaje de error que ven en su propio gestor de bases explica que esa operación debe hacerse desde la plataforma, no desde el cliente de escritorio. - Protección contra fuerza bruta por IP. Una IP que acumula intentos de login fallidos queda bloqueada a nivel de conexión TCP, antes de que el motor siquiera evalúe la contraseña.
Rate limiting en el proxy inverso
Nginx Proxy Manager no expone control de rate limiting en su interfaz (solo tiene toggles de caché, WebSockets y "Block Common Exploits"), así que se inyecta configuración nginx directamente a través del mecanismo de "Custom Nginx Configuration" que sí soporta y que persiste independientemente de los cambios que se hagan desde la UI:
Hasta 10 requests/segundo sostenidas por IP
Ráfagas de hasta 20 requests sin delay
Por encima de eso: 429 Too Many Requests
Tope de 20 conexiones simultáneas por IP
Esta configuración se aplica automáticamente a todo proxy host actual y futuro, sin tener que tocarlo host por host — cualquier subdominio nuevo que se agregue queda protegido desde el primer momento.
Un loop de curl secuencial nunca dispara el límite: el handshake TLS de cada request toma
suficiente tiempo como para que la tasa real quede muy por debajo del límite configurado, aunque
la configuración esté perfectamente bien. Probar rate limiting requiere concurrencia real (por
ejemplo, xargs -P lanzando decenas de requests en paralelo), no una secuencia de peticiones una
por una.
Baneos automáticos
Un servicio de vigilancia observa el log de acceso del proxy inverso y convierte respuestas 429
o errores repetidos en baneos reales a nivel de firewall — aplicados específicamente sobre las
reglas que Docker gestiona (la misma cadena de iptables que el propio Docker usa para publicar
puertos), no sobre las reglas del firewall del sistema operativo, porque de otro modo Docker
seguiría teniendo prioridad y el baneo no tendría efecto real.