Checklist de robustez para sistemas pequeños, basado en OWASP 2025
Los sistemas pequeños rara vez tienen un equipo de seguridad, pero sí tienen los mismos atacantes automatizados que los grandes. Armé una lista de robustez que aplico a cualquier sistema nuevo, sin importar si está hecho en PHP, Node.js o Python. Parte del OWASP Top 10 de 2025 y la completa con lo que en la práctica rompe sistemas modestos: reintentos que duplican, crons que se pisan y secretos mal guardados.
Qué cambió en OWASP 2025
Respecto de la edición de 2021, la lista incorporó dos categorías nuevas: fallas en la cadena de suministro de software, es decir, riesgos que entran por dependencias y herramientas de construcción, y mal manejo de condiciones excepcionales, errores que dejan el sistema en un estado inseguro. Además, la configuración de seguridad incorrecta subió al segundo lugar. Las tres encajan con lo que se ve en hostings compartidos.
Acceso y sesión
- Segundo factor en cualquier inicio de sesión que permita acciones irreversibles o públicas: publicar, cobrar, borrar.
- Límite de intentos de inicio de sesión por IP y por cuenta. Un ataque distribuido no se frena bloqueando solo direcciones.
- Un proxy con firewall de aplicación delante de cada subdominio público, para filtrar antes de que la petición llegue al servidor.
Secretos
- Tokens de terceros cifrados en la base de datos con un algoritmo autenticado, con la clave maestra fuera del repositorio.
- Una política de rotación escrita, aunque la rotación sea manual. Saber cada cuánto se rota vale más que no tener nada.
- Un usuario de base de datos con privilegios mínimos por sistema. Nunca el superusuario compartido de la cuenta.
Integraciones externas
- Idempotencia antes de reintentar cualquier llamada que crea, publica o cobra. Un timeout no significa que la otra plataforma no lo procesó. Reintentar a ciegas es la forma más común de duplicar.
- Contador propio por API, con un tope menor al límite publicado por la plataforma. Frenar antes del error de límite, no reaccionar después.
- Cortocircuito informal: si una plataforma falla en general, dejar de insistir fila por fila y reintentar en bloque más tarde.
Procesos programados
- Bloqueo antes de procesar. En PostgreSQL, seleccionar las filas con bloqueo que salta las ya tomadas; sin base de datos, un bloqueo de archivo. Sin esto, una corrida lenta y la siguiente procesan lo mismo.
- Estados explícitos para cada tarea: pendiente, en proceso, hecha, fallida. Una tarea que quedó "en proceso" por un corte debe poder recuperarse.
- Registro de cada ejecución con su resultado, para saber qué pasó sin reproducirlo.
Condiciones excepcionales
- Ningún bloque que capture errores y no haga nada. Si se captura, se registra y se decide.
- Fallar hacia el lado seguro: si no se puede verificar un permiso, se niega.
- Mensajes de error genéricos hacia el usuario y detallados en el registro interno.
Cadena de suministro
- Archivo de bloqueo de dependencias versionado e instalación reproducible en el despliegue.
- Auditoría de dependencias como parte de la integración continua.
- Pocas dependencias. Cada librería agregada es código de un tercero que corre con los mismos permisos que el tuyo.
Configuración
- Encabezados de seguridad: HSTS, política de contenido, protección contra sniffing de tipos y política de permisos.
- Validación de variables de entorno al arrancar: si falta una, el sistema no inicia en vez de iniciar a medias.
- Un endpoint de salud que consulte la base de datos y responda con error cuando algo falla.
Ninguno de estos puntos requiere herramientas caras. Requieren decidirlos al diseñar, porque agregarlos después a un sistema en producción cuesta varias veces más.