- Sin usar un CDN, se resume cómo bloquear a la mayoría de los bots con implementaciones o configuraciones deficientes combinando protocolo HTTP/rangos IP/señales del cliente/características TCP/huella TLS/compresión de contenido
- Todos los métodos deben ajustarse de forma selectiva, y si no se analizan primero los logs de acceso de 1 a 3 años, se puede terminar bloqueando también a usuarios de VPN/motores de búsqueda/CDN/escuelas/bibliotecas/personas que usan ciertos idiomas
- Bloquear clientes HTTP/1.1 y rangos AS/CIDR de centros de datos puede eliminar muchos bots, pero también puede excluir a motores de búsqueda como GoogleBot y a usuarios legítimos de centros de datos
- La inspección de encabezados en Nginx y los filtros de tamaño de ventana TCP/MSS/TTL en nftables reducen crawlers y escáneres simples, pero pueden generar falsos positivos en entornos legítimos como LTE/VPN/Windows
- Como alternativa a largo plazo, se proponen la detección de huellas TLS JA4 y respuestas exclusivas con Brotli, pero se advierte que no garantizan un bloqueo completo y que no deben usarse en servicios que generan ingresos
Alcance del bloqueo y supuestos de aplicación
- Primero hay que decidir si el objetivo es bloquear algunos bots, la mayoría de los bots o todos los bots
- El enfoque aquí no es detener a todas las herramientas de automatización sofisticadas, sino bloquear de forma relativamente simple a la mayoría de los bots con implementaciones o configuraciones deficientes
- Para cada método también se indica el riesgo de bloquear usuarios legítimos y motores de búsqueda
- Después de compartirse en Hacker News el 26 de julio de 2026, se decidió mover la mayoría de las funciones de bloqueo del blog a un sitio de demostración aparte y convertirlo en una especie de rompecabezas donde el lector lee el método e intenta acceder por su cuenta
- Todas las configuraciones pueden modificarse u omitirse de forma selectiva, y antes de aplicarlas de verdad hace falta suficiente investigación y pruebas
- Como podrían bloquearse usuarios legítimos/sistemas internos de la organización/servicios externos de los que se depende, la responsabilidad de aplicarlo recae por completo en el operador
- No usar en entornos de producción que generan ingresos
Método 1: distinguir por protocolo HTTP
- El riesgo de bloquear usuarios legítimos es bajo, y el riesgo de bloquear algunos motores de búsqueda es intermedio
- Se aprovecha la diferencia de que los navegadores comunes usan HTTP/2.0, mientras que muchos bots usan HTTP/1.1
- Se considera que GoogleBot usa HTTP/1.1, por lo que queda bloqueado con este método
- Los crawlers de Bing y Facebook usan HTTP/2.0
- También pueden bloquearse servicios que obtienen títulos de enlaces o vistas previas cortas por HTTP/1.1
- Opera Mini también queda excluido
- En Nginx se configura para redirigir a otra página o devolver
200, 403 o 444 si $server_protocol no es HTTP/2.0
if ($server_protocol != HTTP/2.0) {
return 403 'Upgrade your client';
}
- Si se devuelve
444, la conexión puede cerrarse sin respuesta adicional
- Cada organización debe evaluar por sí misma si el beneficio obtenido supera la pérdida causada por bloquear el tráfico proveniente de Google Search
Método 2: bloquear rangos IP de centros de datos
- El riesgo de bloquear usuarios residenciales/LTE legítimos es bajo, pero para usuarios de VPN es intermedio, y para motores de búsqueda que operan desde centros de datos es alto
- En los logs de acceso de los últimos 1 a 2 años, se combinan las siguientes señales para encontrar solicitudes sospechosas
- protocolo HTTP
- User-Agent
Accept-Language
Sec-Fetch-Mode
Accept
- Las IP sospechosas se consultan en BGP Tools o en Hurricane Electric BGP Toolkit para verificar el AS al que pertenecen y los Prefix anunciados
- La lista de blackholes de red incluida puede contener también rangos de CDN y motores de búsqueda, por lo que debe aplicarse con criterio
- Antes de las listas separadas, ya se usa una configuración que hace blackhole de los rangos
3/8, 10/8, 11/8, 25/8, 26/8, 38/8, 41/8, 60/8, 61/8, 200/8, 224/3
- Después de copiar la página de Prefix de un AS, se extraen solo los CIDR con una función de shell y se ordenan/se eliminan duplicados/se fusionan
- Se usa sum_cidr.pl y se requiere el módulo de Perl
Net::CIDR::Lite
- El resultado generado se revisa y luego se mueve a archivos
/usr/local/etc/*.netset
- Al iniciar el servidor, cada CIDR se agrega como ruta blackhole
for CflIP in $(grep -E ^[1-9] /usr/local/etc/_cloudflare.netset); do
/sbin/ip route add blackhole "${CflIP}" 2>/dev/null
done
- En el ejemplo, se bloquean todos los rangos de Cloudflare para no aceptar solicitudes a través de Workers, etc.
- Se elige el enrutamiento porque el blackhole routing de Linux usa menos CPU que las reglas ipset del firewall
- También se puede bloquear el rango del proveedor de hosting al que pertenece el servidor actual
- DNS/configuración/servicios internos no deben usar el mismo espacio de direcciones
- Las rutas de gateway conectadas directamente tienen prioridad sobre las rutas blackhole
Método 3: bloqueo por país/proxy/Tor/IP maliciosas
- Se descargan listas del repositorio FireHOL Blocklists y se agregan como rutas blackhole los rangos necesarios
- Como los archivos de listas incluyen comentarios, hay que eliminarlos con
grep -Ev '^#' antes de procesarlos
- En particular se recomiendan estas listas
firehol_abusers_30d.netset
firehol_level2.netset
- Las listas grandes pueden hacer que el script de inicio tarde más en ejecutarse
- También se ofrecen archivos de configuración usados en el servidor real y en la configuración del firewall
Método 4: inspección de señales del cliente HTTP
- Se parte de la idea de que, aunque el User-Agent o los encabezados pueden falsificarse, muchos bots simples priorizan la velocidad y no los falsifican bien
- A las solicitudes de
Curl o Wget se les devuelve texto plano, y a las que incluyen Bot, GPT, LLM o Spider se les devuelve 410 Gone
if ($http_user_agent ~* Curl) { return 200 '\nGNU Terry Pratchett\n\n'; }
if ($http_user_agent ~* Wget) { return 200 '\nGNU Terry Pratchett\n\n'; }
if ($http_user_agent ~* Bot) { return 410 '1000101'; }
if ($http_user_agent ~* GPT) { return 410 '1000101'; }
if ($http_user_agent ~* LLM) { return 410 '1000101'; }
if ($http_user_agent ~* Spider) { return 410 '1000101'; }
- Se inspeccionan algunas cadenas observadas en User-Agent con una sola expresión regular larga para bloquear crawlers/escáneres/herramientas de recolección
- Incluye subcadenas como
Go-http, Java, libwww, okhttp, urllib, python, nmap, zgrab, semrush, shodan, rss, scrap, crawler, headless, github, facebook, google, bing
- Antes de aplicarlo, hay que agregar los User-Agent de 2 a 3 años para comprobar si clientes legítimos reales coinciden con la expresión regular
sort access-user-agents.txt | uniq -c | sort
- Si una solicitud coincidente es HTTP/1.1, se considera con alta probabilidad que sea un bot, aunque GoogleBot se toma como excepción
- Si la solicitud es HTTP/2.0, se revisa además la pertenencia de la IP con herramientas BGP
Sec-Fetch-Mode
- Se agrega
Sec-Fetch-Mode a los logs de acceso y se bloquea si el valor no es cors, no-cors o navigate
if ($http_sec_fetch_mode !~ (cors|no-cors|navigate)) {
return 410 '1000101';
}
Inspección de Referer
- Para impedir solicitudes que insertan contenido o escanean desde otros sitios, se bloquea si
Referer contiene ciertas cadenas
- Se inspeccionan cadenas relacionadas con páginas de administración/motores de búsqueda/redes sociales/criptomonedas/contenido para adultos/escáneres/WordPress
- También se bloquea por separado cierto tipo de bot que afirma usar la página raíz de Google
https://www.google.com/ como Referer
- Es un patrón observado en solicitudes que se hacen pasar por Android antiguo
Restricción de métodos HTTP
- Solo se permiten
GET y POST, que son los necesarios para solicitudes normales del navegador; los demás métodos se bloquean
if ($request_method !~ (^GET$|^POST)) {
return 410 '1000101';
}
- En la aplicación real, se puede restringir con más detalle qué rutas necesitan
POST, o excluirlo por completo si no se usa
Inspección de proxies y forma de navegador
- Si existe el encabezado
X-Forwarded-For, se considera una solicitud por proxy y se bloquea
- También podrían bloquearse entornos legítimos de proxy compartido como escuelas o bibliotecas
- Si el User-Agent no contiene ninguna de estas cadenas:
Linux, BSD, Macintosh, Windows, Mozilla, WhatsApp, se considera una solicitud que no parece venir de un navegador
- También se usa una regla que bloquea si
Accept-Language no contiene en o es
- Hay alta probabilidad de bloquear algunos navegadores y usuarios legítimos que no usan inglés o español
- También se presenta una regla opcional para bloquear por separado configuraciones de idioma que incluyan
br o sy
Bloqueo de escaneo de rutas sensibles
- Si se solicitan los siguientes archivos o rutas, se considera escaneo automático y se bloquea
Método 5: bloquear escáneres TCP con nftables
- Se inspeccionan las características de los paquetes TCP SYN en la cadena
PREROUTING de la tabla raw de nftables
- Para reducir falsos positivos que pueden ocurrir en situaciones de pérdida de paquetes, se especifica la dirección de destino del servidor de ejemplo
172.238.221.88
- Entre los paquetes SYN entrantes a los puertos 80/443, se bloquean los que cumplan estas condiciones
- tamaño de ventana TCP menor a 12,288 bytes
- MSS fuera del rango 1,220~1,460
- Se usa como criterio que los clientes reales emplean tamaños de ventana más grandes y que un MSS fuera de ese rango tiene baja probabilidad de corresponder a un cliente legítimo
- Si se restringe el MSS exactamente a
1460, se vuelve más estricto, pero podría bloquear a la mayoría de los usuarios de LTE y VPN
Restricción opcional basada en TTL
- Si el TTL del TCP SYN es mayor que
128, se puede bloquear a la mayoría de los dispositivos LTE
- Si el TTL es mayor que
64, también se bloquea a la mayoría de los sistemas Windows
- Los criterios de TTL base se explican así
- Linux/Mac/BSD:
64
- Windows:
128
- LTE: un valor mayor que esos
Exclusión del seguimiento de conexiones
- Se marca 80/443 como
notrack para que el tráfico web no entre a la tabla conntrack
- En ese caso, en la tabla filter también hay que configurar manualmente reglas sin estado para las direcciones de envío y recepción
- En el ejemplo, se permite el tráfico entre los puertos de origen del cliente
1000-65535 y los puertos 80/443 del servidor
Método 6: contenido para adultos y encabezados para robots
- Para restringir el acceso a contenido para adultos, se usa el encabezado RTA: Restricted To Adults
- Se considera que los métodos de verificación de edad distintos de RTA existen para rastrear usuarios y monetizar
- En las respuestas de Nginx se agregan siempre los siguientes encabezados
add_header Rating 'RTA-5042-1996-1400-1577-RTA' always;
add_header adult 'porn, sex, politics, religion, philosophy' always;
add_header X-Robots-Tag "none,noindex,nofollow,nosnippet,noai" always;
- Los bots comunes pueden ignorar estos encabezados, pero podrían afectar a motores de búsqueda o bots diseñados para evitar contenido para adultos
Método 7: detección de huellas TLS
- Los métodos 1 a 6 anteriores son heurísticas bastante toscas, y a largo plazo el análisis de huellas TLS puede ser una mejor opción
- JA4 puede aprovecharse bajo la condición de que el bot no cambie su huella TLS para igualarla a la de un navegador normal
- Primero se indica revisar el método de despliegue de Deploying JA4 y luego aplicar FoxIO JA4
Método 8: entregar solo contenido comprimido con Brotli
- Se comprime previamente el contenido del sitio con Brotli y se configura el servidor web para devolver solo los archivos comprimidos
- Se aprovecha que muchos bots no pueden interpretar HTML comprimido con Brotli
- Después de aplicarlo, se confirmó que varios bots dejaron de seguir enlaces de páginas, lo que indica que en realidad no podían parsear el HTML
- En Nginx se configura para servir siempre archivos Brotli estáticos
brotli_static always;
- Los archivos HTML se comprimen previamente de la siguiente forma
cat ./i.html | brotli --best -fncv > ./i.html.br
Método 9: inducir a que los escáneres se identifiquen solos
- Otro método para reducir atacantes principiantes y escáneres que exploran repetidamente rutas de vulnerabilidades se trata en Help Attackers Self Report
1 comentarios
Comentarios de Hacker News
Como alguien que opera varios sitios web públicos y usa herramientas para extraer datos de otros sitios, me pregunto por qué a la gente le preocupan tanto los bots
Incluso WordPress con caché puede manejar alrededor de 1,000 solicitudes por segundo en el VPS más barato, y un sitio estático bien hecho probablemente podría con 10 veces eso. Me pregunto si están sirviendo el blog con algo como Lambda, o si es obsesión, defensa ante vulnerabilidades, o una costumbre de cuando el scraping sí afectaba al servicio real
El repositorio es de código abierto, así que está expuesto a propósito. Ahora mismo me defiendo con una simple verificación de cookies y solo unos pocos bots pasan, pero es una concesión a costa de la visibilidad en buscadores
La idea es mostrar cómo aplicarlo a foros, imageboards, servidores de chat, etc., y todas las opciones se pueden ajustar o desactivar. Antes de aplicarlo en producción habría que validarlo en un servidor de pruebas, y también está bien si solo quieres reírte y seguir de largo
Que tarde unos segundos más en revisar mi servidor IMAP local porque la DMZ está saturada no es el fin del mundo, pero tampoco hay razón para que eso me guste o para seguir permitiéndolo
El fin de semana cerré las interfaces web de viewvc (CVS·Subversion) y hgweb (Mercurial) que había operado por 10~20 años. Llegaban 2.7 millones de solicitudes al día, unas 30 por segundo en promedio, desde IPs de proxies residenciales, lo que cargaba programas antiguos de uWSGI/CGI y otros sitios en el mismo servidor, y además el tráfico se acercaba al límite mensual de 1 TB de mi VPS
Como las combinaciones dinámicas de URLs de VCS pueden llegar a cientos de millones, ni siquiera estaba claro que el caché ayudara, y no valía la pena seguir gastando tiempo afinando el servidor, así que al final tomé una decisión que nos acerca un paso más a un internet centralizado
Si bloqueas todo excepto los agentes de usuario “aprobados”, terminas ayudando al actual monopolio de navegadores y acelerando la distopía. Este es justo el tipo de problema sobre el que RMS viene advirtiendo desde hace décadas
Si de verdad es un problema, deberías bloquear según el volumen de tráfico y la frecuencia de las solicitudes. Yo tampoco puedo acceder a tu sitio, pero no pienso actuar según eso, y como con el DRM, un oponente realmente decidido acabará pasando de todos modos
Aun así, aparte del argumento de que deberías poder usar cualquier navegador, hay que tener especial cuidado con navegadores hechos con código generado al vuelo o no suficientemente auditados frente a sitios maliciosos. Incluso una app lectora podría ser vulnerable a un servidor malicioso si no pasó por una revisión extensa de código de terceros por parte de expertos en pruebas de penetración
Me gusta la idea de agregar un subdominio falso de cpanel que apunte a
169.254.169.254, para que atacantes novatos terminen haciéndole un port scan a su propio proveedor de hosting y puedan ser detectados o bloqueadosLas IP de origen estaban dispersas por todo el mundo, pero el ruido real del escaneo venía de una sola persona
Hay que tener cuidado con el bloqueo basado en IP. Los rangos de IP a veces se reasignan, así que puedes terminar bloqueando a gente equivocada; también he visto varias veces rangos bloqueados por ser de una región o de un datacenter que luego pasan a un ISP residencial
Bloquear HTTP/1.1 también implica un alto riesgo de bloquear usuarios reales que usan navegadores antiguos. Además, hay navegadores que no envían la URL completa en solicitudes de origen cruzado, así que si alguien llega desde una búsqueda de Google, el referer podría apuntar solo a la página raíz de Google; si asumes que eso es una mentira de un bot y lo bloqueas, también podrías perder tráfico proveniente de Google Search
En cambio, sí me parece razonable bloquear HTTP/1.1. Ya pasaron más de 10 años desde que casi todos los navegadores soportan protocolos más nuevos, y si un navegador es así de viejo, gran parte de la web actual ya se le rompe, así que que un sitio personal más no funcione no sería una excepción sino algo cotidiano
Aunque eso implique perder navegadores viejos y herramientas de API, pienso mantener el bloqueo de HTTP/1.1. Si fuera código propietario de un sistema financiero antiguo lo entendería, pero el internet público debe actualizarse por su propio bien
Como bloqueé a Google desde hace mucho, cualquier solicitud que diga venir de Google es mentira. Hago rotar el blog entre varios dominios aleatorios para romper asociaciones y snapshots, y trato de controlar por dónde descubre la gente mis textos
Gracias a eso también recibí pruebas de penetración gratis y concluí que mis defensas y mi pipeline de procesamiento son sólidos. Por presión de supervivencia, el 90% del tráfico bot se movió a VPN y los endpoints de VPN están brillando como árbol de Navidad
Podría incluso ofrecer un feed de IP de acceso de un solo uso, pero el usuario tendría que pasar una verificación adecuada y que se apruebe su propósito. Ese proceso en sí es divertido
Si no se puede leer, puede verse en el respaldo https://archive.ph/d3236
No soy un bot, pero tampoco quiero desactivar iCloud Private Relay para poder leer algo. Según otra respuesta del autor, como sitio de prueba es una buena implementación, pero ojalá otros administradores web no copien tal cual todos los métodos si pueden evitarlo
Por cómo el cuerpo de la respuesta solo muestra 410 y la cadena
Sec-Fetch-Mode:, parece que me clasificó como bot. No hay nada que leer ni ver, así que uno simplemente se va; la web moderna es terribleEl soporte puede verse en https://caniuse.com/?search=sec-fetch-mode y algunos headers pueden revisarse en https://nochan.net/.env
PR_END_OF_FILE_ERROR, lo que indica que no pude pasar ni el handshake de TLSEstoy pensando en quitar el contador de visitas, porque calculo que más del 99% del tráfico web son bots o agentes. La cifra no significa nada y hace que el sitio parezca mucho más concurrido de lo que realmente es, pero dudo en actuar por miedo a impedir que personas reales lean los textos o descarguen libros
Si hace falta bloquear, por lo general una lista de permitidos funciona mejor que una lista de bloqueados, y si no puedes aplicar una lista de permitidos, quizá este método tampoco sea una buena solución
Herramientas como Cloudflare y Anubis pueden causar problemas graves de accesibilidad, así que prefiero limitar la frecuencia de solicitudes. Es más limpio sin dañar la accesibilidad, y para problemas temporales también funcionan bien los bloqueos cortos por IP
En lo personal, analizo los logs HTTP con fail2ban y bloqueo por N horas las IP que piden URL prohibidas en
robots.txt, rutas comowp-login.php, o que sobrepasan con demasiada frecuencia el límite de solicitudes. Ahora mismo estoy probando Anubis en la interfaz web de GitSolo con fail2ban se puede frenar bastante bien, pero durante los primeros meses hay que ajustarlo con mucho detalle al entorno
Primero detecté con el filtro
failregex = ^ - \\S+ \\[\\] ".*?" 40[034]y luego fui agregando a listas más específicas; ahora llevo unas 80 expresiones regulares y desde hace mucho no aparece ninguna solicitud que llegue siquiera al filtro general40[034]Eso sí, detrás de un balanceador de carga o un proxy hace falta algún método para obtener la IP real, así que tanto fail2ban como el método del texto original se vuelven engorrosos
Por estos comentarios y por mis intentos de acceso, parece que está bloqueando todo el tráfico normal, no solo bots
Los domingos es cuando más se ven navegadores y apps raras que la gente usa para recorrer la web, y entre semana predominan los navegadores comunes y mayoritarios, así que sirve como buena prueba