Implementar un Tarpit en Nginx: Atrapa a los Escáneres Maliciosos
Un tarpit responde a los escáneres a unos 10 bytes por segundo, así que se quedan esperando en vez de reintentar al instante como hacen tras un 403 — y una sola opción de Brotli desactivó el mío en silencio durante meses.

Si alguna vez has revisado los logs de tu servidor, seguramente habrás visto innumerables intentos de acceso a archivos como /.env, /wp-login.php, /.git/config o /admin. Se trata de escáneres automatizados que sondean tu servidor en busca de vulnerabilidades. Aunque bloquearlos con una response 403 o 404 funciona, hay un enfoque mucho más satisfactorio: atraparlos en un tarpit.
TL;DR — Atrapa escáneres en un tarpit lento de Nginx
5 puntos clave- Un tarpit gotea los datos lentamente (unos 10 bytes/segundo) para que los escáneres maliciosos se queden atascados en lugar de reintentar al instante como hacen tras un 403/404.
- Tres piezas en Nginx: una carga útil aleatoria grande con el módulo Perl,
limit_ratepara limitar la entrega y unlog_formatdedicado que fuerza el status 418 para un parseo limpio. - Las rutas sensibles devuelven 418 (
/.env,/.git, backups, exploits de CMS, dotfiles) yerror_page 418 = @tarpitlas redirige al snippet de respuesta lenta. - Un map de IPs de confianza fija la rate a 0 y devuelve un 403 normal, de modo que el tráfico de administración nunca queda atrapado accidentalmente.
- CrowdSec banea automáticamente a los reincidentes mediante un parser y un escenario leaky (p. ej. 3 impactos en 5 minutos); Fail2Ban y el reporte a AbuseIPDB son alternativas.
Lo que descubrí al medir de verdad mi propio tarpit
El tarpit de arriba no es un ejercicio de laboratorio: lleva tiempo corriendo en este sitio en producción, registrando 418 en cada captura mientras sirve 200 para mantener enganchado al cliente, tal y como se describe más arriba. Hace poco descubrí que llevaba un tiempo sin cumplir la segunda mitad de ese trabajo, y nada en los logs lo delataba: cada captura seguía mostrando el reparto esperado de 200/418, así que sobre el papel parecía funcionar perfectamente.
El fallo: la compresión anulaba el estrangulamiento
Mi tarpit de producción no sirve la cadena aleatoria de Perl de la guía — sirve una página animada de señuelo, nedry.html (255.864 bytes), seguida de unos 10 MB de relleno con bytes a cero, para un payload combinado de 10.255.882 bytes. limit_rate solo estrangula los bytes que realmente viajan por la red, y Nginx lo aplica después de que se ejecute la compresión. Brotli reducía esa respuesta de ~10 MB a 189.208 bytes (los 189.368 que se ven en el log en crudo incluyen las cabeceras HTTP), y mi limit_rate_after estaba fijado en 300 KB — cómodamente por encima del tamaño comprimido, pero muy lejos del payload real. El estrangulamiento sencillamente nunca se activaba: cada escáner descargaba los 10,25 MB completos a máxima velocidad, en una fracción de segundo, y seguía su camino. El umbral de 300 KB en sí estaba bien elegido — nedry.html por sí solo pesa ~250 KB, calculado para que la animación visible siga cargando rápido para quien no esté siendo atrapado — el relleno es lo que lo rompía en silencio.
El arreglo, y lo que cambió
El arreglo fue una línea, gzip off; brotli off;, en el snippet del tarpit, validada con nginx -t y recargada.
| Métrica | Antes | Después |
|---|---|---|
| Tiempo hasta completarse | 0,23 s | 20 s (timeout del cliente) |
| Bytes recibidos | 10.255.882 | 255.872 (la animación, nada más) |
La imagen a nivel de log coincide. Comparando las 14 horas antes del arreglo con una ventana de 9 horas después, la mediana de bytes servidos por captura pasó de 189.368 a 306.948 — por primera vez, por encima del umbral de limit_rate_after, que es exactamente el aspecto que tiene “el estrangulamiento por fin se activa”. También esperaba que las capturas por hora cayeran con fuerza a medida que los escáneres se quedaran atascados en vez de disparar decenas de peticiones rápidas, y así fue (266/hora antes, 14/hora después) — pero no presento esa cifra como algo probado por sí sola: la ventana “después” se adentra en la noche, cuando el tráfico de escaneo es naturalmente menor, así que parte de la caída podría deberse simplemente al ciclo diario de escaneo y no al arreglo. Confirmarlo de forma rigurosa exige comparar las mismas horas en días distintos, no dos tramos consecutivos. Las cifras de bytes no tienen ese problema — son consecuencia directa y mecánica de desactivar la compresión, algo que la variación de tráfico no podría producir.
Cómo verificar que tu propio tarpit funciona de verdad
La lección transferible aquí: un tarpit que sirve contenido compresible puede estar completamente inoperativo mientras sus logs parecen perfectamente sanos, porque el status code y el recuento de capturas no cambian. Si tienes uno corriendo, comprueba estas tres cosas en vez de fiarte solo del log.
Dos formas de rellenar el payload, y su compromiso
Hay dos formas honestas de construir el relleno de varios megabytes, y ninguna es gratis — presento las dos en vez de fingir que la que uso hoy es sencillamente “la correcta”:
- Relleno de bytes a cero con la compresión desactivada (lo que corre hoy). Simple de generar y fácil de razonar, pero frágil: depende de que nada en la cadena vuelva a comprimir la respuesta. Cualquier proxy intermedio que aplique su propio gzip o Brotli colapsa de nuevo los 10 MB a ~189 KB y anula el tarpit en silencio — sin error, sin alerta, solo un estrangulamiento que deja de estrangular sin avisar.
- Bytes aleatorios en lugar de ceros. Incompresibles por construcción, así que el tarpit funciona haya o no compresión activa en cualquier punto de la cadena, y sobrevive a proxies intermedios que el relleno de ceros no soporta. El coste: el fichero nunca comprime, ni siquiera en los casos en que interesaría (por ejemplo, al servirlo por un enlace lento), y generar y regenerar unos megabytes de aleatoriedad genuina cuesta más trabajo que un flujo de ceros.
Hoy uso la opción 1 porque era lo que podía desplegar de inmediato tras encontrar el fallo — pero es la más frágil de las dos, y ahora sé exactamente qué aspecto tiene “frágil” cuando falla en silencio.
¿Qué es un tarpit?
Un tarpit (también conocido como “tar pit” o “sticky honeypot”) es un mecanismo de seguridad de red diseñado para ralentizar a los atacantes respondiendo deliberadamente a sus request a una velocidad extremadamente lenta. El nombre proviene del fenómeno natural de los pozos de alquitrán — formaciones geológicas donde los animales quedan atrapados en alquitrán viscoso y no pueden escapar.
En ciberseguridad, un tarpit hace lo mismo digitalmente: acepta conexiones entrantes de actores maliciosos pero gotea datos tan lentamente que las herramientas del atacante se quedan atascadas, desperdiciando su tiempo y recursos mientras esperan una response que nunca llega a completarse. Para más contexto, consulta la excelente visión general de Hedgehog Security.
Historia y orígenes
El concepto de tarpit en ciberseguridad surgió a finales de los años 90 y principios de los 2000, durante un período en el que los gusanos de red y las herramientas de escaneo automatizado comenzaron a proliferar. El tarpit más famoso fue LaBrea, creado por Tom Liston alrededor de 2001.
LaBrea funcionaba a nivel de red, respondiendo a paquetes TCP SYN dirigidos a direcciones IP sin usar y creando “máquinas virtuales pegajosas” que atrapaban a los escáneres de gusanos. Cuando los gusanos Code Red y Nimda se estaban propagando rápidamente, LaBrea demostró ser notablemente eficaz para frenar su expansión.
Evolución de los tarpits
El concepto de tarpit ha evolucionado más allá de las implementaciones a nivel de red:
Implementaciones Destacadas de Tarpits
OpenBSD spamd (2003) - El tarpit de correo electrónico que introdujo el greylisting. Cuando un remitente en lista negra se conecta, spamd ralentiza deliberadamente la conversación SMTP, enviando un byte cada vez. Los servidores de correo legítimos reintentan; los spammers desisten. Este enfoque inspiró muchas implementaciones modernas de tarpit.
Endlessh (2019) - Creado por Chris Wellons, este tarpit SSH explota el RFC 4253: antes del intercambio de versión SSH, los servidores pueden enviar “otras líneas de datos”. Endlessh envía datos aleatorios continuamente a intervalos de ~10 segundos, atrapando a los escáneres SSH indefinidamente. ¡Algunas conexiones han durado semanas!
HTTP Tarpits (esta guía) - Tarpits a nivel de aplicación que utilizan funcionalidades del servidor web como limit_rate para gotear datos lentamente a request HTTP maliciosas. Perfectos para atrapar escáneres de vulnerabilidades que buscan archivos sensibles.
¿Por qué usar un tarpit en lugar de bloquear?
| Enfoque | Ventajas | Desventajas |
|---|---|---|
| Bloqueo (403/404) | Inmediato, pocos recursos | El atacante puede reintentar al instante |
| Rate Limiting | Controla el volumen | Puede afectar a usuarios legítimos |
| Tarpit | Desperdicia recursos del atacante, proporciona inteligencia | Mantiene conexiones del servidor abiertas |
Los tarpits ofrecen varias ventajas frente al bloqueo simple:
- Agotamiento de recursos: Los escáneres automatizados tienen conexiones limitadas. Mantenerlos atascados reduce su capacidad de escaneo.
- Recopilación de inteligencia: Las conexiones registradas en el tarpit revelan patrones de IP de los atacantes y las rutas objetivo.
- Impacto psicológico: Los atacantes que descubren que han caído en un tarpit pueden evitar tu servidor en el futuro.
- Fallo de herramientas mal escritas: Algunas herramientas de escaneo no gestionan bien las respuestas lentas y pueden fallar.
Implementación en Nginx
Vamos a implementar una solución tarpit completa y lista para producción en Nginx. La estrategia consta de tres componentes:
- Generar contenido lento: Crear una carga útil aleatoria grande
- Limitar la entrega: Usar
limit_ratepara controlar el bandwidth - Registrar para análisis: Usar un formato de log especializado que fuerza el status code a 418 (aunque devolvamos 200) para que parsers como CrowdSec puedan detectarlo fácilmente.
Paso 1: preparar Nginx (bloque http)
Necesitamos definir nuestros formatos de log y variables map en el nginx.conf principal. Esta configuración permite incluir IPs de confianza en una lista blanca (como tu IP de casa o VPN) ¡para que no te atrapes a ti mismo!
http {
# ... existing config ...
# 1. Map to identify trusted IPs (Localhost, VPN, etc.)
map $remote_addr $is_trusted_ip {
127.0.0.1 1;
::1 1;
# Add your static IP here if you have one
# 1.2.3.4 1;
default 0;
}
# 2. Dynamic Tarpit Rate
# Trusted IPs get 0 (unlimited), others get 10 bytes/s
map $is_trusted_ip $tarpit_rate {
1 0;
0 10;
}
# 2b. Only log tarpitted requests (avoid trusted IPs)
map $is_trusted_ip $tarpit_loggable {
1 0;
0 1;
}
# 3. Special Log Format for Tarpit
# We force the status code to 418 in the log, even though we return 200 to the client.
# This allows CrowdSec to easily identify tarpit hits without complex parsing.
log_format tarpit_418_fixed escape=none '$remote_addr - $remote_user [$time_local] "$request" 418 $body_bytes_sent "$http_referer" "$http_user_agent" "$host"';
# 4. Generate random content (requires nginx-mod-http-perl)
perl_set $slow_content 'sub {
my $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
my $result = "";
for (1..100000) {
$result .= substr($chars, int(rand(length($chars))), 1);
}
return $result;
}';
}Paso 2: crear el snippet del tarpit
Crea un snippet reutilizable que gestione el throttle y el logging.
# Log to dedicated tarpit log only for tarpitted requests
access_log /var/log/nginx/tarpit_access.log tarpit_418_fixed if=$tarpit_loggable;
# Bypass for Trusted IPs - Return standard 403 instead of Tarpit
# This saves you from waiting 2 hours if you accidentally hit a protected path!
if ($is_trusted_ip) {
return 403;
}
# Dynamic bandwidth throttling (0 for trusted, 10 for others)
limit_rate $tarpit_rate;
# Start throttling after the first byte
limit_rate_after 1;
# Send the slow response
add_header Content-Type text/plain;
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
add_header Pragma "no-cache";
return 200 $slow_content;Paso 3: definir las rutas sensibles (las “trampas”)
En lugar de añadir lógica de logging a cada location (lo cual es un lío), simplemente devolvemos 418 para cualquier ruta sensible. Gestionaremos este código de error globalmente en el server block.
/etc/nginx/snippets/sensitive_files_tarpit.conf
# =============================================================================
# Sensitive Files Tarpit Protection
# =============================================================================
# Environment and configuration files
location ~ /\.env { return 418; }
location ~ /\.git { return 418; }
location ~ /\.svn { return 418; }
location ~ /\.hg { return 418; }
# Server configuration files
location ~ /\.(htaccess|htpasswd) { return 418; }
# Backup and sensitive file extensions
location ~* \.(bak|backup|old|orig|save|swp|tmp|sql|db|sqlite|sqlite3)$ { return 418; }
# PHP/CMS exploit paths
location ~* (phpinfo|adminer|phpmyadmin|wp-login|xmlrpc|wp-admin|wp-config)\.php$ { return 418; }
# Common scanner/exploit paths
location ~* ^/(config|admin|administrator|login|cgi-bin|scripts|shell|cmd|console) { return 418; }
# Catch-all for dotfiles (excluding .well-known)
location ~ /\.(?!well-known) {
return 418;
}Paso 4: configurar el server block
Ahora unimos todo usando error_page 418. Este es el “pegamento mágico” que hace que la arquitectura sea limpia.
server {
listen 443 ssl;
server_name example.com;
# ... SSL and other configuration ...
# =========================================================
# TARPIT HANDLER
# =========================================================
# 1. Catch 418 errors
error_page 418 = @tarpit;
# 2. Redirect them to the tarpit snippet
location @tarpit {
include /etc/nginx/snippets/tarpit.conf;
}
# =========================================================
# SITE CONFIGURATION
# =========================================================
# Include the traps
include /etc/nginx/snippets/sensitive_files_tarpit.conf;
location / {
try_files $uri $uri/ =404;
}
}Paso 5: probar la configuración
Valida y recarga Nginx:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Prueba el tarpit con un timeout para no quedarte esperando eternamente:
* Trying [::1]:443...
* Connected to example.com (::1) port 443
* TLS 1.3 connection using TLS_AES_256_GCM_SHA384
> GET /.env HTTP/2
< HTTP/2 200
< content-type: text/plain
< cache-control: no-store, no-cache, must-revalidate, max-age=0
* Operation timed out after 5000 milliseconds with 50 bytes received
curl: (28) Operation timed outLa conexión se estableció, se recibieron 50 bytes (5 segundos × 10 bytes/segundo), y luego nuestro timeout entró en acción. ¡En la realidad, el escáner de un atacante esperaría mucho más!
Integración con CrowdSec
Mientras el tarpit malgasta el tiempo del atacante, podemos ir más allá baneando automáticamente a los reincidentes. CrowdSec puede analizar el log del tarpit y crear reglas de firewall.
Crear un parser de CrowdSec
CrowdSec puede leer el archivo /var/log/nginx/access.tarpit para identificar IPs maliciosas:
name: crowdsec/nginx-tarpit
description: "Parse Nginx tarpit access logs"
filter: "evt.Parsed.program == 'nginx-tarpit'"
onsuccess: next_stage
statics:
- meta: service
value: http
- meta: log_type
value: tarpit
- meta: source_ip
expression: "evt.Parsed.remote_addr"
- meta: http_path
expression: "evt.Parsed.request"
nodes:
- grok:
pattern: '%{IPORHOST:remote_addr} - %{DATA:user} \[%{HTTPDATE:time}\] "%{WORD:method} %{DATA:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status} %{NUMBER:bytes}'
apply_on: messageCrear un escenario
Define cuándo banear una IP (por ejemplo, tras 3 impactos en el tarpit en 5 minutos):
type: leaky
name: crowdsec/nginx-tarpit-scan
description: "Detect and ban IPs triggering the Nginx tarpit"
filter: "evt.Meta.service == 'http' && evt.Meta.log_type == 'tarpit'"
leakspeed: 5m
capacity: 3
groupby: "evt.Meta.source_ip"
blackhole: 1h
labels:
service: http
type: scan
remediation: trueReportar IPs maliciosas: contribuir a la defensa colectiva
Uno de los aspectos más potentes de ejecutar un tarpit es la inteligencia que recopilas. Cada conexión atrapada revela la IP del atacante, las rutas objetivo y los patrones de tiempo. Pero estos datos se vuelven exponencialmente más valiosos cuando se comparten con la comunidad de seguridad.
¿Por qué reportar IPs maliciosas?
Entre los beneficios de reportar se incluyen:
- Detección temprana: Otras organizaciones pueden bloquear amenazas que has identificado antes de ser atacadas
- Reconocimiento de patrones: Los datos agregados revelan ataques coordinados, botnets y campañas de malware
- Reducción de la superficie de ataque: Las IPs reportadas son a menudo bloqueadas por ISPs y herramientas de seguridad a nivel global
- Reciprocidad de la comunidad: Los colaboradores reciben acceso a listas de bloqueo más amplias y completas
Integración con AbuseIPDB
AbuseIPDB es una plataforma de inteligencia de amenazas impulsada por la comunidad con más de 100.000 colaboradores. Puedes tanto consultar la reputación de una IP como reportar IPs maliciosas a través de su API.
Consultar la reputación de una IP
Antes de bloquear, verifica el nivel de amenaza:
Reportar IPs maliciosas desde los logs del tarpit
Crea un script para reportar automáticamente las capturas del tarpit:
#!/bin/bash
# Report IPs from tarpit log to AbuseIPDB
# Usage: Run via cron every hour
set -euo pipefail
ABUSEIPDB_KEY="${ABUSEIPDB_KEY:-}"
LOGFILE="/var/log/nginx/access.tarpit"
REPORTED="/var/log/nginx/reported_ips.txt"
REPORT_LOG="/var/log/nginx/abuseipdb_reports.log"
# Validate API key
if [[ -z "$ABUSEIPDB_KEY" ]]; then
echo "[$(date -Iseconds)] ERROR: ABUSEIPDB_KEY not set" >> "$REPORT_LOG"
exit 1
fi
# Ensure files exist
touch "$REPORTED" "$REPORT_LOG"
# Get unique IPs from last hour
awk -v d1="$(date --date='-1 hour' '+%d/%b/%Y:%H')" \
'$4 ~ d1 {print $1}' "$LOGFILE" | sort -u | while read -r ip; do
# Skip if already reported today
grep -q "$ip" "$REPORTED" 2>/dev/null && continue
# Report to AbuseIPDB with error handling
response=$(curl -s -w "\n%{http_code}" "https://api.abuseipdb.com/api/v2/report" \
-H "Key: $ABUSEIPDB_KEY" \
-H "Accept: application/json" \
--data-urlencode "ip=$ip" \
--data-urlencode "categories=21,15" \
--data-urlencode "comment=Vulnerability scanner trapped in HTTP tarpit." \
2>&1) || true
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
if [[ "$http_code" == "200" ]]; then
echo "$ip $(date +%Y-%m-%d)" >> "$REPORTED"
echo "[$(date -Iseconds)] OK: Reported $ip" >> "$REPORT_LOG"
else
echo "[$(date -Iseconds)] FAIL: $ip (HTTP $http_code) $body" >> "$REPORT_LOG"
fi
doneListas de bloqueo de la comunidad CrowdSec
A diferencia de AbuseIPDB (que es una consulta pasiva), CrowdSec funciona como un “firewall masivamente multijugador”. Cuando tu Security Engine detecta una amenaza, comparte la señal con la red, y tú recibes actualizaciones de listas de bloqueo que contienen amenazas detectadas por otros usuarios.
| Nivel | Tamaño | Requisito |
|---|---|---|
| Lite | 3.000 IPs | Cuenta gratuita, sin contribución |
| Community | ~15.000 IPs | Contribución regular de señales |
| Premium | Ilimitado | Suscripción de pago |
La lista de bloqueo Community se actualiza en tiempo real y está adaptada a tu stack — si ejecutas WordPress, recibirás automáticamente IPs de amenazas específicas de WordPress.
Técnicas avanzadas
Combinar con rate limiting
Para mayor protección, combina el tarpit con rate limiting para evitar sobrecargar tu servidor:
# Define rate limit zone
limit_req_zone $binary_remote_addr zone=tarpit_zone:10m rate=1r/s;
location @tarpit {
limit_req zone=tarpit_zone burst=5 nodelay;
limit_rate 10;
# ... rest of tarpit config
}Tarpit para User-Agents específicos
Apunta a escáneres maliciosos conocidos por User-Agent. Los escáneres más comunes incluyen sqlmap (inyección SQL), Nikto (escáner de vulnerabilidades web), Nmap (escáner de red), masscan (escáner de puertos) y ZGrab (banner grabber):
map $http_user_agent $is_scanner {
default 0;
"~*sqlmap" 1;
"~*nikto" 1;
"~*nmap" 1;
"~*masscan" 1;
"~*zgrab" 1;
}
server {
if ($is_scanner) {
return 418;
}
# ... rest of server
}Monitorización de tu tarpit
Analizar los logs del tarpit
Como forzamos el status code a 418 en nuestro formato de log tarpit_418_fixed, filtrar los ataques es increíblemente sencillo, incluso si están mezclados con otros logs:
847 /.env
312 /wp-login.php
201 /.git/config
156 /admin/
98 /phpmyadmin/
87 /.htaccess
65 /config.php
43 /backup.sql
38 /shell.php
29 /xmlrpc.phpIPs más infractoras
Identifica los escáneres más persistentes:
423 185.234.xx.xx
287 45.148.xx.xx
156 194.169.xx.xx
98 23.94.xx.xx
67 89.248.xx.xxResultados en el mundo real
Implementar la arquitectura lista para producción con logging forzado a 418 ha mejorado significativamente la visibilidad:
- Señal clara: El status code 418 actúa como una señal de alta fidelidad para “intención maliciosa confirmada”.
- Cero falsos positivos: Gracias al map de IPs de confianza, el tráfico de administración nunca se atrapa accidentalmente en el tarpit.
- Protección de recursos: El bypass de rate limit garantiza que el tráfico válido fluya sin problemas mientras los atacantes se quedan atascados en el carril lento.
- Integración con CrowdSec: La lógica del parser se volvió trivial — simplemente hacer coincidir
status == 418es suficiente para banear una IP, independientemente de la ruta solicitada.
Conclusión
Un tarpit es una adición creativa y eficaz a tu arsenal de seguridad. Aunque no debería sustituir un endurecimiento adecuado y controles de acceso, proporciona:
- Desperdicio de recursos para escáneres automatizados
- Recopilación de inteligencia sobre patrones de ataque
- Baneo automático cuando se combina con CrowdSec o Fail2Ban
- Un elemento disuasorio psicológico para los atacantes
La implementación en Nginx es directa usando solo unas pocas directivas (limit_rate, error_page y bloques location). Combinado con logging y una herramienta de seguridad como CrowdSec, se crea una defensa por capas que no solo bloquea a los atacantes, sino que les hace pagar por sus intentos de intrusión.
Preguntas frecuentes
¿Qué es un tarpit en seguridad de red?
Un tarpit (o "sticky honeypot") es un mecanismo de seguridad que ralentiza a los atacantes respondiendo deliberadamente a sus request a una velocidad extremadamente lenta. Acepta la conexión pero gotea los datos tan lentamente que las herramientas del atacante se quedan atascadas, desperdiciando su tiempo y recursos.
¿Por qué usar un tarpit en lugar de bloquear con un 403 o 404?
A diferencia del bloqueo, que permite al atacante reintentar al instante, un tarpit malgasta sus conexiones limitadas, recopila inteligencia sobre sus IPs y rutas objetivo, e incluso puede provocar fallos en herramientas de escaneo mal programadas. El compromiso es que mantiene conexiones del servidor abiertas, por lo que conviene ser selectivo con qué rutas lo activan.
¿Cómo implemento un tarpit HTTP en Nginx?
Usa tres piezas: una carga útil aleatoria grande (generada con el módulo Perl), la directiva limit_rate para limitar la entrega a unos 10 bytes/segundo y un formato de log dedicado. Las rutas sensibles devuelven 418, y un manejador error_page 418 = @tarpit redirige esas request al snippet de respuesta lenta.
¿Por qué forzar el status code 418 en el log si el tarpit devuelve 200?
El cliente debe recibir un 200 OK para seguir conectado y atascado, pero codificar 418 directamente en el log_format ofrece a parsers como CrowdSec o Fail2Ban una señal clara y de alta fidelidad para identificar y banear las request tarpiteadas sin parseo complejo.
¿Cómo evito atraparme a mí mismo o a IPs de confianza?
Define un map de Nginx con IPs de confianza (localhost, tu VPN, tu IP estática) y establece su tarpit rate a 0. El snippet del tarpit devuelve un 403 estándar para las IPs de confianza y las excluye del log, de modo que el tráfico de administración nunca queda atrapado accidentalmente.
¿Cómo puedo banear automáticamente las IPs atrapadas por el tarpit?
Integra CrowdSec con un parser y un escenario de tipo leaky (por ejemplo, banear tras 3 impactos en el tarpit en 5 minutos) que lea el log del tarpit. Alternativas más sencillas incluyen Fail2Ban, y puedes reportar las IPs capturadas a AbuseIPDB para contribuir a la defensa colectiva.
Lecturas y recursos adicionales
- tarpit Wikipedia
- sticky honeypot jmrp.io
- la excelente visión general de Hedgehog Security hedgehogsecurity.co.uk
- LaBrea labrea.sourceforge.io
- Tom Liston giac.org
- Code Red Wikipedia
- Nimda Wikipedia
- OpenBSD spamd OpenBSD
- Endlessh GitHub
- Chris Wellons nullprogram.com
- Nginx Nginx
- CrowdSec CrowdSec
- Fail2Ban GitHub
- AbuseIPDB AbuseIPDB
- sqlmap sqlmap.org
- Nikto GitHub
- Nmap nmap.org
- masscan GitHub
- ZGrab GitHub
- página del homelab jmrp.io