En el mapa de ataques hay una mancha densa sobre un país, y se sugiere por sí sola la regla «prohibirlo por completo». No dará casi nada: cambiar el país de salida le cuesta al atacante unos minutos, mientras que bajo la prohibición caerán tus propios visitantes y tú mismo cuando viajes. Peor aún: un rastreador visible que llega desde una sola nube se mudará a direcciones residenciales después del bloqueo y dejará de distinguirse de las personas.
A continuación hay cinco pasos que en ese mismo servidor sí dan resultado: cortar los escáneres, limitar el ritmo, no cortar lo necesario y, si de todos modos hace falta, bloquear correctamente. Todo se comprueba y se configura en una sola sesión.
Paso 1. Ver quién crea realmente la mancha
Primero localiza el registro de peticiones. En un servidor con varios sitios, access.log suele estar vacío, mientras que las entradas van al registro del propio servidor virtual:
sudo ls -lS /var/log/apache2/*access*.log /var/log/apache2/*requests*.log 2>/dev/null
En todos los comandos siguientes se sustituye por el archivo que haya quedado arriba de esa lista. Primero las direcciones que encabezan la jornada, y luego qué pide exactamente la que está arriba:
sudo awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
sudo grep '^203\.0\.113\.' /var/log/apache2/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
El segundo comando responde a la pregunta principal. Si en la salida aparecen decenas de páginas distintas de tu sitio, se trata de un recolector de contenido: es inofensivo y basta con no contarlo como visitante. Si allí figuran /wp-login.php, /.env, /phpmyadmin y otras cosas que no tienes, es un escáner, y de él se ocupa el paso 2. Para nginx los registros están en /var/log/nginx/, los campos son los mismos.
Paso 2. Una cárcel para las peticiones a lo que no tienes
La ruta de la petición no se puede falsificar — ella misma es la intención, a diferencia de la dirección y del User-Agent. El filtro /etc/fail2ban/filter.d/web-probes.local:
[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD) /(wp-login\.php|wp-admin|xmlrpc\.php|\.env|\.git/|phpmyadmin|administrator/)
ignoreregex =
La cárcel /etc/fail2ban/jail.d/web-probes.local:
[web-probes]
enabled = true
port = http,https
filter = web-probes
logpath = /var/log/apache2/*access.log
maxretry = 1
findtime = 1h
bantime = 1d
Aquí maxretry = 1 está justificado: no existen accesos casuales a un panel de administración ajeno. Aplicarlo y comprobar que el filtro captura líneas en tu propio registro:
sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/web-probes.local
sudo systemctl reload fail2ban && sudo fail2ban-client status web-probes
Paso 3. Limitar el ritmo
El escáner y el rastreador se delatan por la velocidad, con independencia del país del que vengan. Treinta páginas por minuto desde una sola dirección es un umbral que no afecta a una persona que hojea un catálogo:
[http-flood]
enabled = true
port = http,https
filter = apache-overflows
logpath = /var/log/apache2/site_access.log
maxretry = 30
findtime = 60
bantime = 1h
El detalle clave es qué registro figura en logpath. Si el patrón abarca el registro del propio panel de gestión o del área de administración, te bloquearás a ti mismo: una sola de sus páginas arrastra una decena de peticiones a estilos y scripts, y treinta se acumulan en un par de clics. Por eso al panel se le da un archivo de registro propio, que no coincide con el patrón de la cárcel, y a los archivos estáticos un tiempo de caché largo, para que el navegador no los vuelva a pedir en cada página. El síntoma, si ocurre de todos modos: el HTML llega, el diseño no, la página se queda colgada. Quitar el bloqueo:
sudo fail2ban-client set http-flood unbanip 203.0.113.10
Paso 4. Proteger lo que no se puede cortar
Antes de activar los bloqueos, anota las excepciones — de lo contrario, lo primero que caerá bajo ellos será lo necesario:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24 66.249.64.0/19
Qué tiene que estar sin falta en esa línea y por qué:
- Tu propia dirección o la subred de la oficina. La causa más frecuente de perder el acceso al servidor es una regla propia, no un ataque;
- El rango
66.249.64.0/19. El robot de búsqueda de Google se identifica por el User-Agent, pero la parte de él que ejecuta JavaScript llega con unChrome/Linuxcorriente y no se presenta. Cualquier regla del tipo «bloquear el tráfico de los centros de datos» golpea precisamente a esa parte, tras lo cual las páginas caen silenciosamente del índice. Una dirección sospechosa se puede comprobar con una consulta inversa:dig -x 66.249.66.1 +shortdebe devolver un nombre en la zonagooglebot.com; - Las direcciones de las notificaciones de pago. Los webhooks de los sistemas de pago llegan desde servidores de AWS y Azure. Si cierras esas nubes por completo, las confirmaciones de pago dejarán de llegar, y lo sabrás el día en que un cliente escriba que el dinero se ha cobrado pero el acceso no está. Los rangos se toman de la documentación de tu proveedor de pagos.
Paso 5. Si el bloqueo hace falta de todos modos, bloquea una subred, no un país
Un engrosamiento constante desde una sola red, que se mantiene durante días y va acompañado de peticiones de un mismo tipo, es un único ejecutor que recorre una lista. Ese caso se bloquea de forma puntual y temporal:
sudo ufw deny from 198.51.100.0/22 to any
sudo ufw status numbered
Con el segundo comando, apunta el número de la regla: el bloqueo habrá que quitarlo por él, sudo ufw delete <número>. Acuerda contigo mismo un plazo — por ejemplo, un mes — y anota la retirada en el calendario. Las reglas puestas «para siempre» se convierten al cabo de un año en una lista que nadie se atreve a tocar, porque nadie recuerda por qué esas direcciones acabaron allí.
Para saber qué subred bloquear, parte de la dirección del primer paso: whois 198.51.100.17 | grep -iE 'route|cidr|netname'.
Qué cambia después de estos cinco pasos
Los escáneres se cortan por intención y no por procedencia, y se atrapan en la primera petición. Los rastreadores topan con el límite de ritmo. El robot de búsqueda y las notificaciones de pago siguen pasando. El único bloqueo amplio que queda es puntual, con un plazo conocido y un motivo claro.
El mapa, por su parte, no desaparece, pero su papel cambia: no sirve para cerrar países, sino para advertir el engrosamiento en sí y compararlo con lo que había la semana anterior. Para eso hace falta un historial y no una instantánea de la jornada en curso. Qué aspecto tiene un mapa así junto al registro de bloqueos y a la lista de puertos abiertos lo muestran las páginas de demostración de abajo.