# 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_chat` sin 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-roles` v1.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` ```sql 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` ```sql 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_errors` para verificar `h-captcha-response` via `POST 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_pending` sin email confirmado → redirigido a `/pending-driver/` con mensaje "Confirma tu email" - Endpoint `GET /autobooking/v1/confirm-email?token=xxx` → valida token, marca `ab_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` ```sql 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 en `wp-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/3` documentos 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 1. Un bot no puede crear más de 5 cuentas por hora desde la misma IP 2. Un conductor nuevo no puede acceder al dashboard sin confirmar su email 3. Un conductor no puede ser aprobado sin los 3 documentos subidos 4. GPS de USA + IP de Rusia → bloqueado con mensaje claro 5. La API Key de Google Maps no aparece en el HTML de ninguna página pública 6. El flujo de selección de rol al login (`choose-role`) sigue funcionando sin cambios 7. Las páginas de registro mantienen su diseño visual actual