Limitar acceso de bots a nuestra web por horas

Últimamente la mayoría de webs de clientes con los que estoy trabajando es con un sistema a medida en su propio servidor, ya sea un VPS de 2 GB de RAM y 1 procesador o un dedicado con 128 GB de RAM y 32 procesadores.

Sea cual sea el tamaño del servidor, los administro con GridPane, hoy por hoy sin lugar a dudas el mejor panel para montar un stack de WordPress realmente profesional. Su precio parte de los $200 mensuales y debemos sumarle el precio de cada servidor que utilicemos, pero si te dedicas seriamente a esto, realmente merece la pena.

Desde luego que no es un servicio para la gran mayoría de las instalaciones, porque además deberemos ajustarlo convenientemente para cada cliente con un uso intensivo de la consola y archivos de configuración y no de una forma gráfica, por lo que si la consola no es lo vuestro…

El caso es que un cliente al que le administro el servidor, un Vultr de Alta frecuencia de 4 GB de RAM, con un WooCommerce con unos 14.500 productos; estaba dando un rendimiento excelente en cuanto a tiempos de carga (caché de página y de objetos con Redis), pero la mayor parte del tiempo tenía la CPU en un 150%, esto ya por más de un mes.

Este dato me da una idea del buen rendimiento de Vultr, al menos en los servidores High Frequency Compute, ya que con otros VPS ya habría dado errores, dejado de funcionar, estados 502, etc… y este servidor seguía funcionando sin inmutarse.

Después de indagar un poco por los logs y ver todo más o menos correcto, bueno, muchos plugins a mejorar, pero eso era tema de una segunda fase; como digo, después de una búsqueda, me encontré con un tráfico muy elevado con el siguiente identificador de agente de usuario «Mozilla/5.0 (compatible; Pinterestbot/1.0; +http://www.pinterest.com/bot.html)«.

Logs Pinterest Bot

Comprobada la IP de las peticiones y el ASN (AS14618 AMAZON-AES), compruebo que es el bot auténtico de Pinterest.

Los DNS los gestiono desde Cloudflare, desde donde ejecuto también una serie de reglas personalizada en el firewall para bloquear determinadas peticiones (en breve escribiré un artículo sobre este tema). Así que el primer paso es bloquear las peticiones desde Cloudflare, algo muy sencillo:

Vamos a Firewall -> Herramientas -> Bloqueo de agente de usuario y creamos una regla de bloqueo. De nombre le pongo «Bot de Pinterest», como acción selecciono desafío (en lugar de bloquearlo) y de agente de usuario ponemos «Mozilla/5.0 (compatible; Pinterestbot/1.0; +http://www.pinterest.com/bot.html)».

Regla de bloqueo de agente de usuario

Activo la regla, monitorizo en vivo los logs del servidor con:

Regla de bloqueo en Cloudflare
# tail -f -n30 /var/log/nginx/domain.com.access.log

Y enseguida veo que las peticiones del bot de Pinterest comienzan a desaparecer, están siendo bloqueadas por el firewall de Cloudflare, bueno, en realidad le está enviando el desafío y si no lo supera, se bloquea la petición.

Y veo que la CPU vuelve a unos valores en torno al 30%, pero hay un problema. Se está utilizando Pinterest para el comercio y se debe habilitar que su bot pase de vez en cuando a escanear productos y sus fotos.

Consumo CPU servidor Vultr

Pinterest no nos permite seleccionar cuando vendrá su bot y con que frecuencia de rastreo. Pero en cambio sí que hace caso a la directiva Craw-delay respetando valores de hasta un máximo de 1 https://help.pinterest.com/en/business/article/pinterest-crawler, por lo que la primera acción es modificar el archivo robots.txt y añadirle lo siguiente:

User-agent: Pinterestbot
Crawl-delay: 1

Ahora lo ideal sería decirle: «Pinterest, puedes escanear mi web entre las 10 de la noche y las 8 de la mañana, después no vengas…» así que, después de darle una vuelta se me ocurrió la idea:

Tengo creada una regla en Cloudflare que bloquea las peticiones de Pinterest, y que puedo activar y desactivar, ¿no?, y Cloudflare tiene una API, ¿no?

Pues allá vamos. Después de mirar un poco la documentación y crear una clave API para el dominio del cliente en cuestión, hice unas cuantas pruebas con Postman y enseguida conseguí activar y desactivar la regla mediante la API y la clave recién creada.

Petictiones a la API de Cloudflare desde Postman

Bien, ya casi está, ahora podemos hacer la llamada desde el servidor con un cron, pero hay un servicio del que ya os hablé en otro artículo y que me parece una maravilla, además de ser gratuito cron-job.org

Entro en cron-job y compruebo que puedo hacer peticiones PUT, que puedo enviar cabeceras personalizadas y un JSON en el cuerpo de la petición… pues ya está. Programo dos cron desde el servicio. Uno para activar la regla todos los días a las 8 de la mañana, con los que lanzará el desafío a las peticiones de Pinterest y otro cron a las 10 de la noche que desactivará la regla por lo que se permitirán todas las peticiones desde Pinterest.

Cron jobs enable disable Cloudflare rule

Ambas tareas cron son iguales, la única diferencia es el parámetro paused que será true para detener la tarea y false para mantenerla activa.

La parte del API que nos interesa en este caso es la de Update UserAgent Rule, así que en la nueva tarea cron, en primer lugar ponemos la url https://api.cloudflare.com/client/v4/zones/IDENTIFICADOR-DE-ZONA/firewall/ua_rules/ID-DE-LA-REGLA

Para el identificador de zona, si desplegamos API bajo nuestra regla en Cloudflare, nos muestra la url con dicho identificador y si hacemos una petición a GET https://api.cloudflare.com/client/v4/zones/IDENTIFICADOR-DE-ZONA/firewall/ua_rules con los parámetros necesarios de identificación obtendremos el ID de la regla.

Cron job, opciones básicas

A continuación, activamos la tarea cron en la hora deseada y marcamos las opciones que queramos, como que guarde la respuesta de las peticiones, que nos avise en caso de fallo, etc. y nos vamos a Advanced.

En la pestaña de avanzado añadimos dos cabeceras personalizadas, una para autenticarnos con el API Token:

«Authorization» y valor «Bearer la_api_key_generada«

Y otra para indicarle que el contenido será JSON:

«Content-Type» y valor «application/json«

En método cambiamos de GET a PUT y en Request body los datos JSON a enviarle:

{
	"id": "id-de-la-regla",
	"description": "Bot de Pinterest",
	"paused": false,
	"mode": "challenge",
	"configuration": {
		"target": "ua",
		"value": "Mozilla/5.0 (compatible; Pinterestbot/1.0; +http://www.pinterest.com/bot.html)"
	}
}
Cron job, opciones avanzadas

Con esta petición activaríamos la regla y con otra en la que cambiemos de "paused": false a "paused": true la desactivaríamos de nuevo.

Recordad que si administráis varias cuentas de Cloudflare con autorización (en mi caso tengo varias de clientes administradas desde la mía), para crear el Token de API, deberéis autorizar solo su cuenta. Y dentro de la misma solo el dominio que queráis y en los permisos Editar los Servicios de Firewall.

Token de API Cloudflare

Cuando creamos Token que autoriza cambios, limitad siempre al máximo lo que se puede hacer con los mismos y que podáis revocarlos fácilmente.

Espero que os haya podido servir de ayuda.

4 comentarios en «Limitar acceso de bots a nuestra web por horas»

    • Gracias, Mariano, me alegro de que te parezca de utilidad y como se puede adaptar a todo tipo de reglas… da mucho juego.

      Saludos, Carlos Longarela.

      Responder

Deja un comentario