hjs.es ← inicio
← volver a inicio en progreso

Consola privada de operaciones

Una herramienta web privada para el día a día con servidores Plesk: una base de datos de IPs que atacan, la consulta de quién está detrás de cada una y un generador de comandos de Fail2ban e iptables. La regla de diseño más importante: nunca ejecuta nada en los servidores. Solo genera texto que reviso y pego yo.

PHP MariaDB Fail2ban iptables RDAP AbuseIPDB CSP

Contexto

En servidores web con Plesk, Fail2ban bloquea solo los ataques más evidentes, y la mayoría de sus bloqueos duran minutos: las mismas IPs vuelven una y otra vez contra SSH, el correo o los WordPress de los clientes. Decidir cuáles merecen un bloqueo largo, comprobar de quién son, escribir el comando para cada servidor y acordarse de qué se bloqueó dónde se hacía a mano, con notas sueltas.

Restricción de partida: en los servidores de clientes no se puede instalar nada propio (ni agentes, ni scripts que llamen a casa). Así que la herramienta tenía que vivir aparte y no depender de tocar los servidores.

Diseño

01

Pegar cualquier cosa, guardar solo IPs válidas

Se pega lo que salga en el servidor: IPs sueltas, la salida de fail2ban-client status o un grep de un log. La herramienta extrae las IPs, las normaliza (la misma IPv6 escrita de dos formas es una sola), rechaza las privadas y reservadas y las que están marcadas como seguras, y si una ya estaba le suma una vez en vez de duplicarla.

02

Saber de quién es antes de bloquear

Cada IP o rango se consulta a la vez en ipinfo (ubicación, ASN, proveedor), en RDAP (el registro oficial: rango asignado, titular, contacto de abuso) y en AbuseIPDB (reputación). Las peticiones van en paralelo con curl_multi y el resultado se resume en un veredicto: intrusiva, sospechosa o sin reportes. Así no se bloquea por error a Google, a un monitor o a un cliente.

03

Generar comandos, nunca ejecutarlos

Se eligen las IPs (por país, por las más vistas o a mano), el servidor y el método, y sale el texto listo para copiar: fail2ban-client set JAIL banip IP o reglas de iptables en una cadena propia. Por defecto, una orden simple por línea: en algunos servidores compartidos no se puede pegar un bucle. Antes de generar se vuelve a validar todo (el jail y cada IP), porque ese texto se pega como root.

04

IPs sueltas y rangos, siempre por separado

Bloquear un rango entero es una medida grave que puede dejar fuera a gente legítima. Por eso una IP cuenta por sí misma aunque caiga dentro de un rango guardado, y los rangos tienen su propia vista: nunca se mezclan en un mismo bloqueo sin decidirlo expresamente.

05

Registro de qué se bloqueó y dónde

Cada vez que se copian comandos queda un lote con el servidor, el método y las IPs. Cada acción (altas, consultas, bloqueos, borrados) se apunta en un registro, y las IPs que no se ven en 12 meses se pueden purgar: una IP es un dato personal y no tiene sentido guardarla para siempre.

06

Privada y con poco que atacar

Subdominio con contraseña del servidor y, además, una comprobación propia en el código. Base de datos separada de la de la web pública, con un usuario que solo puede leer y escribir filas. CSP estricta: ni una línea de JavaScript dentro del HTML. Las claves de los servicios externos viven fuera de la web.

Ficha de una IP consultada: veredicto, país, rango registrado y proveedor, con la opción de añadirla a la lista
Consultar una IP: país, rango registrado, proveedor y si ya está en la lista (datos de prueba).
Lista de IPs agrupadas por país, con el servidor, el método de bloqueo y el botón para copiar los comandos
Revisar y bloquear: IPs agrupadas por país, servidor, método y comandos listos para copiar (datos de prueba).

Problemas por el camino

✗

Un salto de línea pasaba la validación del jail

Las pruebas automáticas encontraron que "recidive\n" se aceptaba como nombre de jail válido: en PHP, el $ de una expresión regular admite un salto de línea al final. En un texto que acaba pegado como root, eso es justo lo que no puede pasar.

Solución: el modificador /D en todas las validaciones de ese tipo, y una batería de pruebas (IPs con trucos como 1.2.3.4; rm -rf / o $(id), rangos, IPv6) que se lanza tras cada cambio.
✗

Un archivo subido podía cambiar lo que se copia

La herramienta también guarda scripts y chuletas que se suben desde la web. Un .svgz, un .xht o un archivo sin extensión que empezara por <html> se habría abierto como página dentro del subdominio privado, y desde ahí podría alterar lo que copian los botones.

Solución: más extensiones prohibidas y, sobre todo, mirar el contenido: se rechaza cualquier archivo que empiece como una página web, se llame como se llame.
✗

Servidores antiguos que no se comportan como los nuevos

En servidores con Plesk y CentOS 6 el jail de bloqueo semanal no existe, la base de datos de Fail2ban puede estar corrupta (database disk image is malformed) y el iptables 1.4.7 no tiene la opción -C para comprobar si una regla ya existe.

Solución: el método de bloqueo se elige por servidor (Fail2ban con el jail que exista, o iptables directo), los comandos de iptables no usan -C, y las guías de diagnóstico explican cómo reconocer y arreglar esos casos.
✗

RDAP no encontraba las IPv6

Las consultas de IPv6 al servicio RDAP volvían siempre vacías, aunque en la web del registro sí aparecían.

Causa: la IP se mandaba codificada en la URL, como manda la buena práctica: los : viajaban como %3A, y el servicio no los entendía.
Solución: mandarla tal cual, solo después de haberla validado como IP (así no puede llevar nada más).

Resultado

El ciclo completo en un solo sitio: sacar las IPs atacantes de los logs del servidor, consultarlas, decidir, copiar los comandos y dejar constancia. La decisión sigue siendo siempre de una persona, y la herramienta no puede ejecutar nada aunque alguien llegara a entrar en ella.

Alrededor de la lista de IPs, la misma consola guarda chuletas de comandos y guías de diagnóstico paso a paso (servidor lento, disco lleno, web con error 500, correo que no sale, ataque en curso) con los comandos listos para copiar.

Proyectos relacionados