Volver a la wiki

Auditoría Suprema · network sub-área 4 (Devices/Backups/Groups) — Seguridad de credenciales y configuraciones

Resumen

Cuarta tanda de la Auditoría Suprema del módulo network (sesión 115). Enfoque en la seguridad de credenciales, backups de configuración y grupos de dispositivos. Se cerraron 30 hallazgos confirmados (4 ALTA, 14 MEDIA, 12 BAJA) mediante unificación de gates de autorización y validaciones defensivas.

Sin cambios visibles para usuarios administradores. Es endurecimiento de permisos (readonly ya no ve secretos) + honestidad de la interfaz (restore_backup ya no finge éxito).

Hallazgos ALTA (4)

ALTA #1: Fuga de credenciales descifradas (get_device_credentials)

Problema: El endpoint /api/network/device/{device_id}/credentials devolvía usuario/contraseña SSH + enable en claro a cualquier usuario de la org, incluso con rol readonly (que tiene permiso network:view por defecto).

Impacto: Un usuario de solo lectura podía obtener las credenciales SSH vivas de cualquier dispositivo y conectarse directamente.

Fix: Gateado con require_perm(request, "network", "edit"). Paralelo al fix anterior en core (/credentials/{id}/decrypt — sa1).

Fuentes:

ALTA #2: Server-Side Request Forgery en force_check_device

Problema: El health check (POST /api/network/device/{device_id}/check) abría un socket socket TCP desde el servidor hacia cualquier IP en la config, sin validar que no fuera una dirección interna (RFC1918, loopback, metadata). Un atacante podía forzar escaneos de servicios internos.

Impacto: Exposición de servicios privados, pivoting potencial.

Fixes:

  1. Gate require_perm(request, "network", "edit") (antes sin autenticación clara).
  2. Guard is_private_ip(ip_address) — rechaza loopback, RFC1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), CGNAT (100.64.0.0/10).
  3. Validación de puerto: int(port) y rango 1–65535 (antes aceptaba “500” como string).
  4. Timestamps aware (timezone.now() en lugar de datetime.now()).

Fuentes:

ALTA #3: Lectura de configuraciones con secretos en claro

Problema: Tres endpoints permitían descargar/ver configuraciones en texto plano (incluyendo communities SNMP, enable secrets, material criptográfico):

Un usuario readonly (que tiene network:view por defecto) podía descargar la configuración completa.

Matiz importante: list_backups (solo metadatos, sin config_text) SÍ se queda en view — permite al readonly ver que existen backups.

Fixes:

Fuentes:

ALTA #4: restore_backup finge éxito (Reglas 13/15)

Problema: El endpoint /api/network/backup/{backup_id}/restore respondía 200 {success: true, "restore initiated"} sin restaurar nada. Era un placeholder. Violaba Reglas 13 (no mentir sobre estado) y 15 (fallos explícitos).

Fix: Ahora devuelve 501 Not Implemented tras validar existencia/propiedad del backup. El mensaje es honesto: “Configuration restore is not implemented yet”.

Fuentes:

Hallazgos MEDIA (14)

Hallazgos BAJA (12)

Cambios en files

network/api/backups.py

network/api/devices.py

network/api/device_groups.py

network/api/common.py

network/utils.py

tests/api/test_network_sa4.py (nuevo)

Seguridad: Resumen de cambios de permisos

Antes (caótico):

Después (unificado):

network:view   → list_* endpoints (metadata sin secretos)
network:edit   → lectura/mutación de credenciales + configs + device status
network:admin  → mutaciones de backup + delete_device_group + force_check_device

Relación con anteriores

Pendientes (deferred a PRs propias)

Véase también

Subir