8.8 KiB
8.8 KiB
AutoBooking Security — Diseño Opción B
Fecha: 2026-05-30
Estado: Aprobado por usuario
Alcance: Anti-spam, anti-ghost registrations, rate limiting, IP geolocation backup, documentos de conductor
1. Contexto y problema
AutoBooking es una plataforma de transporte en WordPress (autobooking.online). Los problemas identificados:
- Cuentas fantasma: cualquier bot puede registrarse como conductor o pasajero sin verificación
- Spam en chat:
wp_autobooking_chatsin rate limiting - API Key de Google Maps expuesta en código fuente PHP y en HTML del frontend
- GPS spoofeable: el plugin geo-restrict confía 100% en coordenadas enviadas por el cliente
- Sin rate limiting en ningún endpoint REST ni en login/registro
Funcionalidades existentes que se preservan sin cambios:
- Selección de rol al login (Snippets #15 + #18:
after-login→choose-role) - Páginas de registro con diseño Forminator
- Plugin
autobooking-rolesv1.1.0 (roles driver, driver_pending, corporate_admin) - Todos los plugins de dashboard (driver, passenger, corporate, admin)
2. Arquitectura
Componentes nuevos
| Componente | Tipo | Propósito |
|---|---|---|
autobooking-security.php |
Plugin nuevo | Central de seguridad: rate limiting, nonces, IP geo |
wp_ab_rate_limits |
Tabla DB | Registro de hits por IP/endpoint |
wp_ab_blocked_ips |
Tabla DB | IPs bloqueadas con TTL |
wp_ab_driver_documents |
Tabla DB | Documentos de conductor (licencia, seguro, foto) |
| hCaptcha en registro | Hook Forminator | Verificación anti-bot en registro de conductores |
Componentes modificados
| Componente | Cambio |
|---|---|
autobooking-admin-dashboard.php |
Mover GMAPS_KEY a wp_options; mostrar documentos pendientes en tab Conductores |
autobooking-geo-restrict.php |
Agregar verificación de IP via ip-api.com con caché transient |
3. Rate Limiting
Tabla wp_ab_rate_limits
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
ip VARCHAR(45) NOT NULL
endpoint VARCHAR(80) NOT NULL
hits INT UNSIGNED NOT NULL DEFAULT 1
window_start DATETIME NOT NULL
KEY (ip, endpoint, window_start)
Tabla wp_ab_blocked_ips
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
ip VARCHAR(45) NOT NULL UNIQUE
reason VARCHAR(120) NOT NULL DEFAULT ''
blocked_at DATETIME NOT NULL
expires_at DATETIME NOT NULL
KEY (ip, expires_at)
Límites configurados
| Endpoint / Acción | Límite | Ventana | Bloqueo automático |
|---|---|---|---|
| Registro de usuario | 5 intentos | 60 min | 24 h |
wp_login_failed |
10 fallos | 15 min | 2 h |
POST /autobooking/v1/* |
120 requests | 1 min | 30 min |
| Chat (write) | 1 mensaje | 2 seg | 10 min |
Implementación
- Hook
register_post→ verificar IP antes de crear usuario - Hook
wp_login_failed→ contar fallos de login por IP - Filter
rest_dispatch_request→ contar requests REST por IP - Helper
ab_sec_check_rate( $ip, $endpoint, $limit, $window_sec )→ bool - Helper
ab_sec_block_ip( $ip, $reason, $hours )→ void - IPs en whitelist (configurables en tab CONFIG del admin dashboard) nunca se bloquean
4. Anti-Ghost Registration
Flujo de registro de conductor
1. Usuario llena formulario Forminator en /driver-registration/
2. hCaptcha valida (verificación server-side)
3. Rate limit: máx 5 registros / hora / IP
4. WordPress crea usuario con rol driver_pending
5. Email de confirmación enviado → cuenta inactiva hasta confirmar
6. Conductor sube 3 documentos desde /pending-driver/
7. Admin aprueba en dashboard → rol pasa a driver
hCaptcha
- Servicio gratuito (hcaptcha.com) — requiere crear cuenta y obtener site key + secret key
- Hook
registration_errorspara verificarh-captcha-responseviaPOST https://api.hcaptcha.com/siteverify - Si falla → error visible en el formulario, registro rechazado
- Site key y secret key guardadas en
wp_options:ab_hcaptcha_site_key,ab_hcaptcha_secret
Email confirmation
- Token de confirmación en
wp_usermeta:ab_email_token(SHA256 random),ab_email_token_expires(24h) - Usuario con rol
driver_pendingsin email confirmado → redirigido a/pending-driver/con mensaje "Confirma tu email" - Endpoint
GET /autobooking/v1/confirm-email?token=xxx→ valida token, marcaab_email_confirmed = 1 - Si el token expiró (>24h): mostrar página "Token expirado" con botón para reenviar email de confirmación (endpoint
POST /autobooking/v1/resend-confirmation)
Tabla wp_ab_driver_documents
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
driver_id BIGINT UNSIGNED NOT NULL
doc_type ENUM('license','insurance','vehicle_photo') NOT NULL
file_url VARCHAR(512) NOT NULL DEFAULT ''
expiry_date DATE NULL
status ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending'
reviewed_by BIGINT UNSIGNED NULL
reviewed_at DATETIME NULL
created_at DATETIME NOT NULL
KEY (driver_id, doc_type)
KEY (status)
Regla de aprobación
- Conductor sube docs desde
/pending-driver/— tipos permitidos: JPG, PNG, PDF (máx 5 MB por archivo), guardados enwp-content/uploads/ab-driver-docs/{user_id}/ - Admin ve docs en tab CONDUCTORES → cola de aprobación
- Botón "Aprobar conductor" solo habilitado si los 3 documentos existen
- Rechazo envía email automático con motivo al conductor
5. IP Geolocation Backup
Modificación a /geo/check
1. Recibir lat/lng del cliente
2. Detectar país por bounding boxes (lógica existente — sin cambios)
3. Si país por GPS está en allowed list:
a. Obtener IP del request (X-Forwarded-For validado, o REMOTE_ADDR)
b. Si IP es privada/local (127.x, 10.x, 192.168.x) → confiar en GPS
c. Consultar caché: transient "ab_geo_ip_{md5(ip)}" TTL=86400s
d. Si no hay caché → llamar ip-api.com/json/{ip}?fields=countryCode
e. Si ip-api.com falla (timeout/error) → fail open, permitir acceso
f. Si país por IP != país por GPS → retornar allowed=false, mensaje "Ubicación inconsistente"
4. Retornar resultado normal
- ip-api.com: gratuito, 45 req/min — el caché de 24h por IP lo mantiene muy por debajo del límite
- El bloqueo por discrepancia es duro (no solo advertencia)
6. Google Maps API Key
Problema
const GMAPS_KEY = 'AIzaSyD3...' hardcodeada en autobooking-admin-dashboard.php:17 y expuesta en el HTML de la página de admin.
Solución en código
- Eliminar la constante
GMAPS_KEY - Leer siempre de
get_option('ab_gmaps_key', '')— este campo ya existe en el tab CONFIG del admin dashboard - El campo ya estaba en la UI; solo hay que eliminar el fallback a la constante
Acción manual requerida (fuera del código)
- Ir a Google Cloud Console → Credenciales → Restricciones de la key
- Agregar restricción HTTP: solo
*.autobooking.online/*
7. Modificaciones al Admin Dashboard
Tab CONDUCTORES
- Columna "Docs" en cola de aprobación: muestra
X/3documentos subidos - Botón "Aprobar" deshabilitado si hay documentos faltantes
- Modal muestra miniaturas de los 3 documentos con links para ver tamaño completo
Tab CONFIG — nueva sección "Seguridad"
- Campo: IPs en whitelist (textarea, una por línea)
- Tabla: IPs bloqueadas actualmente con columnas IP, Motivo, Expira, botón Desbloquear
- Contador: intentos bloqueados en las últimas 24 h
8. Preservación de funcionalidad existente
| Feature | Estado | Acción |
|---|---|---|
| Snippets #15 + #18 (choose-role) | Sin cambios | No tocar |
| Snippet #14 (login gating) | Sin cambios | No tocar |
| Snippet #19 (registro override) | Sin cambios | Solo agregar hCaptcha al hook |
| Páginas Forminator | Sin cambios | Solo agregar campo h-captcha-response |
| autobooking-roles plugin | Sin cambios | No tocar |
| Driver / Passenger / Corporate dashboards | Sin cambios | No tocar |
9. Archivos a crear/modificar
CREAR:
wp-content/plugins/autobooking-security/autobooking-security.php
MODIFICAR:
wp-content/plugins/autobooking-admin-dashboard/autobooking-admin-dashboard.php
wp-content/plugins/autobooking-geo-restrict/autobooking-geo-restrict.php
ACCIONES MANUALES:
1. Google Cloud Console → restringir GMAPS_KEY a *.autobooking.online/*
2. hcaptcha.com → crear cuenta gratuita, obtener site_key y secret_key
3. Activar plugin autobooking-security desde WP Admin → Plugins
10. Criterios de éxito
- Un bot no puede crear más de 5 cuentas por hora desde la misma IP
- Un conductor nuevo no puede acceder al dashboard sin confirmar su email
- Un conductor no puede ser aprobado sin los 3 documentos subidos
- GPS de USA + IP de Rusia → bloqueado con mensaje claro
- La API Key de Google Maps no aparece en el HTML de ninguna página pública
- El flujo de selección de rol al login (
choose-role) sigue funcionando sin cambios - Las páginas de registro mantienen su diseño visual actual